/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 
/* vim: set ts=2 et sw=2 tw=80: */
#if !defined(NET_FOSSIL_SCM_FSL_HASH_H_INCLUDED)
#define NET_FOSSIL_SCM_FSL_HASH_H_INCLUDED
/*
   Copyright (c) 2013 D. Richard Hipp

   This program is free software; you can redistribute it and/or
   modify it under the terms of the Simplified BSD License (also
   known as the "2-Clause License" or "FreeBSD License".)

   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.

   Author contact information:
     drh@hwaci.com
     http://www.hwaci.com/drh/

  *****************************************************************************
   This file declares public APIs relating to generating hash values
   hashing.
*/

#include "fossil-util.h" /* MUST come first b/c of config macros */

#if defined(__cplusplus)
extern "C" {
#endif

  /**
      Various set-in-stone constants used by the API.
   */
  enum fsl_hash_constants {
  /**
      The length, in bytes, of fossil's hex-form UUID strings.
   */
  FSL_UUID_STRLEN = 40,
  /**
      The length, in bytes, of a hex-form MD5 hash.
   */
  FSL_MD5_STRLEN = 32
  };


  typedef struct fsl_md5_cx fsl_md5_cx;
  typedef struct fsl_sha1_cx fsl_sha1_cx;

  /**
      The hash string of the initial MD5 state. Used as an
      optimization for some places where we need an MD5 but know it
      will not hash any data.

      Equivalent to what the md5sum command outputs for empty input:

      @code
      # md5sum < /dev/null
      d41d8cd98f00b204e9800998ecf8427e  -
      @endcode
   */
#define FSL_MD5_INITIAL_HASH "d41d8cd98f00b204e9800998ecf8427e"

  /**
      Holds state for MD5 calculations. It is intended to be used like
      this:

      @code
       unsigned char digest[16];
       char hex[FSL_MD5_STRLEN+1];
       fsl_md5_cx cx = fsl_md5_cx_empty;
       // alternately: fsl_md5_init(&cx);
       ...call fsl_md5_update(&cx,...) any number of times to
       ...incrementally calculate the hash.
       fsl_md5_final(&cx, digest); // ends the calculation
       fsl_md5_digest_to_base16(digest, hex);
       // digest now contains the raw 16-byte MD5 digest.
       // hex now contains the 32-byte MD5 + a trailing NUL
      @endcode
   */
  struct fsl_md5_cx {
    int isInit;
    fsl_uint32_t buf[4];
    fsl_uint32_t bits[2];
    unsigned char in[64];
  };
#define fsl_md5_cx_empty_m {                                    \
    1/*isInit*/,                                                \
    {/*buf*/0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 },   \
    {/*bits*/0,0},                                              \
    {0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,                  \
        0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,               \
        0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,               \
        0,0,0,0}}

  /**
      A fsl_md5_cx instance which holds the initial state
      used for md5 calculations. Instances must either be
      copy-initialized from this instance or they must be
      passed to fsl_md5_init() before they are used.
   */
  extern const fsl_md5_cx fsl_md5_cx_empty;

  /**
      Initializes the given context pointer. It must not be NULL.  This
      must be the first routine called on any fsl_md5_cx instances.
      Alternately, copy-constructing fsl_md5_cx_empty has the same effect.

      @see fsl_md5_update()
      @see fsl_md5_final()
   */
  void fsl_md5_init(fsl_md5_cx *cx);

  /**
      Updates cx's state to reflect the addition of the data
      specified by the range (buf, buf+len]. Neither cx nor buf may
      be NULL. This may be called an arbitrary number of times between
      fsl_md5_init() and fsl_md5_final().

      @see fsl_md5_init()
      @see fsl_md5_final()
   */
  void fsl_md5_update(fsl_md5_cx *cx, void const * buf, fsl_size_t len);

  /**
      Finishes up the calculation of the md5 for the given context and
      writes a 16-byte digest value to the 2nd parameter.  Use
      fsl_md5_digest_to_base16() to convert the digest output value to
      hexidecimal form.

      @see fsl_md5_init()
      @see fsl_md5_update()
      @see fsl_md5_digest_to_base16()
   */
  void fsl_md5_final(fsl_md5_cx * cx, unsigned char * digest);

  /**
      Converts an md5 digest value (from fsl_md5_final()'s 2nd
      parameter) to a 32-byte (FSL_MD5_STRLEN) CRC string plus a
      terminating NUL byte. i.e.  zBuf must be at least
      (FSL_MD5_STRLEN+1) bytes long.

      @see fsl_md5_final()
   */
  void fsl_md5_digest_to_base16(unsigned char *digest, char *zBuf);

  /**
      The md5 counterpart of fsl_sha1sum_buffer(), identical in
      semantics except that its result is an MD5 hash instead of an
      SHA1 hash and the resulting hex string is FSL_MD5_STRLEN bytes
      long plus a terminating NUL.
   */
  int fsl_md5sum_buffer(fsl_buffer const *pIn, fsl_buffer *pCksum);

  /**
      The md5 counterpart of fsl_sha1sum_cstr(), identical in
      semantics except that its result is an MD5 hash instead of an
      SHA1 hash and the resulting string is FSL_MD5_STRLEN bytes long
      plus a terminating NUL.
   */
  char *fsl_md5sum_cstr(const char *zIn, fsl_int_t len);

  /**
      The MD5 counter part to fsl_sha1sum_stream(), with identical
      semantics except that the generated hash is an MD5 string
      instead of SHA1.
   */
  int fsl_md5sum_stream(fsl_input_f src, void * srcState, fsl_buffer *pCksum);

  /**
      Reads all input from src() and passes it through fsl_md5_update(cx,...).
      Returns 0 on success, FSL_RC_MISUSE if !cx or !src. If src returns
      a non-0 code, that code is returned from here.
   */
  int fsl_md5_update_stream(fsl_md5_cx *cx, fsl_input_f src, void * srcState);

  /**
      Equivalent to fsl_md5_update(cx, b->mem, b->used). Results are undefined
      if either pointer is invalid or NULL.
   */
  void fsl_md5_update_buffer(fsl_md5_cx *cx, fsl_buffer const * b);

  /**
      Passes the first len bytes of str to fsl_md5_update(cx). If len
      is less than 0 then fsl_strlen() is used to calculate the
      length.  Results are undefined if either pointer is invalid or
      NULL. This is a no-op if !len or (len<0 && !*str).
   */
  void fsl_md5_update_cstr(fsl_md5_cx *cx, char const * str, fsl_int_t len);

  /**
      A fsl_md5_update_stream() proxy which updates cx to include the
      contents of the given file.
   */
  int fsl_md5_update_filename(fsl_md5_cx *cx, char const * fname);

  /**
      The MD5 counter part to fsl_sha1sum_filename(), with identical
      semantics except that the generated hash is an MD5 string
      instead of SHA1.
   */
  int fsl_md5sum_filename(const char *zFilename, fsl_buffer *pCksum);


  /**
      Holds state for SHA1 calculations. It is intended to be used
      like this:

      @code
       unsigned char digest[20]
       char hex[FSL_UUID_STRLEN+1];
       fsl_sha1_cx cx = fsl_sha1_cx_empty;
       // alternately: fsl_sha1_init(&cx)
       ...call fsl_sha1_update(&cx,...) any number of times to
       ...incrementally calculate the hash.
       fsl_sha1_final(&cx, digest); // ends the calculation
       fsl_sha1_digest_to_base16(digest, hex);
       // digest now contains the raw 20-byte SHA1 digest.
       // hex now contains the 40-byte SHA1 + a trailing NUL
      @endcode
   */
  struct fsl_sha1_cx {
    unsigned int state[5];
    unsigned int count[2];
    unsigned char buffer[64];
  };
  /**
      fsl_sha1_cx instance intended for in-struct copy initialization.
   */
#define fsl_sha1_cx_empty_m {\
    {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 },  \
    {0,0},\
    {0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0, \
     0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0\
    }                                                               \
  }

  /**
      fsl_sha1_cx instance intended for copy initialization.
      Its contents are equivalent to those set by fsl_sha1_init().
   */
  extern const fsl_sha1_cx fsl_sha1_cx_empty;

  /**
      Initializes the given context with the initial SHA1 state.  This
      must be the first routine called on an SHA1 context, and passing
      this context to other SHA1 routines without first having passed
      it to this will lead to undefined results.

      @see fsl_sha1_update()
      @see fsl_sha1_final()
   */
  void fsl_sha1_init(fsl_sha1_cx *context);

  /**
      Updates the given context to include the hash of the first len
      bytes of the given data.

      @see fsl_sha1_init()
      @see fsl_sha1_final()
   */
  void fsl_sha1_update( fsl_sha1_cx *context, void const *data, fsl_size_t len);

  /**
      Add padding and finalizes the message digest. If digest is not
      NULL then it writes 20 bytes of digest to the 2nd parameter.

      @see fsl_sha1_update()
      @see fsl_sha1_digest_to_base16()
   */
  void fsl_sha1_final(fsl_sha1_cx *context, unsigned char * digest);

  /**
      Convert a digest into base-16.  digest must be at least 20 bytes
      long and hold an SHA1 digest. zBuf must be at least (FSL_UUID_STRLEN
      + 1) bytes long, for FSL_UUID_STRLEN characters of
      hexidecimal-form SHA1 hash and 1 NUL byte.

      @see fsl_sha1_final()
   */
  void fsl_sha1_digest_to_base16(unsigned char *digest, char *zBuf);

  /**
      Computes the SHA1 checksum of pIn and stores the resulting
      checksum in the buffer pCksum.  pCksum's memory is re-used if is
      has any allocated to it. pCksum may == pIn, in which case this
      is a destructive operation (replacing the hashed data with its
      hash code).

      Return 0 on success, FSL_RC_OOM if (re)allocating pCksum fails.
   */
  int fsl_sha1sum_buffer(fsl_buffer const *pIn, fsl_buffer *pCksum);

  /**
      Computes the SHA1 checksum of the first len bytes of the given
      string.  If len is negative then zInt must be NUL-terminated and
      fsl_strlen() is used to find its length.  The result is a
      FSL_UUID_STRLEN-byte string (+NUL byte) returned in memory
      obtained from fsl_malloc(), so it must be passed to fsl_free()
      to free it. If NULL==zIn or !len then NULL is returned.
   */
  char *fsl_sha1sum_cstr(const char *zIn, fsl_int_t len);

  /**
      Consumes all input from src and calculates its SHA1 hash. The
      result is set in pCksum (its contents, if any, are overwritten,
      not appended to). Returns 0 on success. Returns FSL_RC_MISUSE if
      !src or !pCksum. It keeps consuming input from src() until that
      function reads fewer bytes than requested, at which point EOF is
      assumed. If src() returns non-0, that code is returned from this
      function.
   */
  int fsl_sha1sum_stream(fsl_input_f src, void * srcState, fsl_buffer *pCksum);


  /**
      A fsl_sha1sum_stream() wrapper which calculates the SHA1 of
      given file.

      Returns FSL_RC_IO if the file cannot be opened, FSL_RC_MISUSE if
      !zFilename or !pCksum, else as per fsl_sha1sum_stream().

      TODO: the v1 impl has special behaviour for symlinks which this
      function lacks. For that support we need a variant of this
      function which takes a fsl_cx parameter (for the allow-symlinks
      setting).
   */
  int fsl_sha1sum_filename(const char *zFilename, fsl_buffer *pCksum);


#if defined(__cplusplus)
} /*extern "C"*/
#endif
#endif
/* NET_FOSSIL_SCM_FSL_HASH_H_INCLUDED */
