/*                                             -*- mode:C; fill-column:100 -*-
 *
 * SFBChecksum.c - Cryptographically INSECURE, but fairly fast
 *                 and small LFSR-based checksum
 *
 * Copyright (C) 2008 The Regents of the University of New Mexico.  All rights reserved.
 *
 * This file is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 * USA
 */

/**
  \file SFBChecksum.h A cryptographically insecure but fairly fast and small checksum.

  An #SFBChecksum is a compact, not too slow, fairly ARM friendly, 64 bit checksum, based on a (63
  bit) linear feedback shift register (LFSR).  It is designed to gain reasonable confidence that a
  sequence of data bytes has not been corrupted during transmission.
 
  \attention NOTE WELL: SFBChecksum is \e ONLY aimed at detecting \e innocent changes (e.g.,
  transmission noise, unintentional bugs, code development); it is \e NOT a cryptographic algorithm!
 
  \par To repeat that:
  PAY ATTENTION: Matching SFBChecksum's is \e no defense against malicious intent!
 
  The SFB library uses #SFBChecksum's in several contexts, including to check that code sectors and
  sketches exchanged during \ref SFBCodeFlow.h operations match what is expected.
 
  \usage
  \code
    void setup() { 
      // nothing to do, nothing to do, put some mustard in your shoe
    }
    void loop() {
      SFBCheckum cs;                         // Declare a checksum.  This DOES NOT initialize it!
      SFBChecksumInit(cs);                   // Now cs is ready for use

      SFBChecksumAddByte(cs,'!');            // Add a single byte to the checksum
      SFBChecksumAddBytes(cs, "foobar", 4);  // Add the four bytes 'f', 'o', 'o', 'b'

      u32 someData = 2468;                   // Get some data of some kind
      SFBChecksumAddBytes(cs, (const char *) &someData, sizeof(someData)); // Add it in

      println(SFBChecksumToString(cs));      // Print the current checksum in hexadecimal

      SFBChecksum cs2;                       // Get another, also uninitialized, checksum
      SFBChecksumCopy(cs, cs2);              // Copy from cs to cs2

      if (SFBChecksumEqual(cs2,cs)) println("same");   // Prints 'same'

      for (u32 i = 0; i < 100; ++i)
        SFBChecksumAddByte(cs,random(256));  // Add 100 random bytes to cs

      if (!SFBChecksumEqual(cs2,cs)) println("different"); // Prints 'different', with very high probability

      delay(5000);                           // Wait five seconds, then repeat 
    }
    \endcode

  \author David H. Ackley.  
  \date (C) 2008 All rights reserved.
  \lgpl

 */
#ifndef SFBCHECKSUM_H
#define SFBCHECKSUM_H

#include <inttypes.h>  /* for uint32_t */

#ifdef __cplusplus
extern "C" {
#endif

/**
  The internal representation of an SFBChecksum.  An 'SFBChecksum' is simply an array of two 32 bit
  unsigned ints.  (In other words, the same things that are abbreviated as \c u32 in most of the SFB
  codebase.  They are written out here with their 'more official' abbreviation -- \c uint32_t -- to
  allow to SFBChecksum to 'stand alone'.)
 */
typedef uint32_t SFBChecksum[2];

/**
 * Initialize an #SFBChecksum struct.  May be called at any time; may be called repeatedly; \e must
 * be called before the #SFBChecksum is first used and whenever a new SFBChecksum is being started.
 *
 * @param cs the SFBChecksum to initialize or reinitialize
 *
 * @sideeffect \a cs is initialized.
 */
void SFBChecksumInit(SFBChecksum cs);

/**
 * Incorporate an additional data byte into \a cs, a #SFBChecksum struct.
 *
 * @param cs Pointer to the structure to update.  Must be non-NULL.
 *
 * @param data Byte to incorporate into the running SFBChecksum.
 *
 * @sideeffect \a cs is updated.
 */
void SFBChecksumAddByte(SFBChecksum cs, char data);

/**
 * Incorporate a sequence of additional data bytes into an SFBChecksum
 * struct.  
 *
 * @param cs Pointer to the structure to update.  Must be non-NULL.
 *
 * @param data Pointer to an array of \a length bytes to add to the running SFBChecksum in order,
 *             starting with \c data[0] and including up through \c data[\a length-1].  Must be
 *             non-NULL.
 *
 * @param length Number of bytes in array \a data to use.
 *
 * @sideeffect \a cs is updated (unless \a length is less than 1).
 */
void SFBChecksumAddBytes(SFBChecksum cs, const char * data, int length);

/**
 * Copy one SFBChecksum to another.
 *
 * @param csFrom source SFBChecksum
 *
 * @param csTo destination SFBChecksum
 *
 * @sideeffect \a csTo is updated.
 */
void SFBChecksumCopy(const SFBChecksum csFrom,SFBChecksum csTo);

/**
 * Compare one SFBChecksum to another.
 *
 * @param cs1 one checksum
 *
 * @param cs2 the other checksum
 *
 * @return 1 if and only \a cs1 and \a cs2 contain the same checksum, 0 otherwise
 * 
 */
int SFBChecksumEqual(const SFBChecksum cs1,const SFBChecksum cs2);


/**
 * Access the current SFBChecksum result, as a zero-terminated, 16 character hexadecimal string.
 * Note this function returns a pointer to a statically allocated buffer, so:
 *
 * -# The value returned from this function MUST NOT be 'free()'d.
 * -# The content pointed-to by the return value of this function is only valid until the next call
 *    of #SFBChecksumToString on \e ANY #SFBChecksum struct.
 *
 * Note the pointed-to value is 16 ASCII-encoded hexadecimal characters.
 *
 * @param cs Checksum to read out
 *
 * @return Pointer to a zero-terminated string of 16 hexadecimal characters containing the current
 *         SFBChecksum result.  See limitations above on the use of the pointed-to-data.  Never
 *         returns NULL.
 *
 * @sideeffect The statically allocated \c char* buffer is overwritten, erasing its previous
 *             contents.
 */
const char * SFBChecksumToString(SFBChecksum cs);

/**
 * Initialize an SFBChecksum from a string of 16 ASCII hex characers.  
 *
 * @param cs Checksum to initialize.  Must not be NULL.
 *
 * @param hexString Pointer to an array of at least 16 ASCII hex characters with nothing else (no
 *         leading or embedded whitespace, etc).  Must not be NULL. Routine only looks at first 16
 *         positions, so anything after that is not a problem.
 *
 * @return 1 if cs was successfully initialized from hexString, 
 * @return 0 an invalid (non-hex) ASCII character was encountered.
 *
 * \usage
 * \code
 * void setup() { }
 * void loop() {
 *   SFBChecksum cs;
 *   SFBChecksumInit(cs);
 *   SFBChecksumAddBytes(cs,"bytes",5);
 *   char * str = SFBChecksumToString(cs);           // Get cs as zero-terminated string of hex
 *   println(str);                                   // Print it.
 *
 *   SFBChecksum cs2;
 *   SFBChecksumFromString(cs2,str);                 // Init cs2 from zstring of hex
 *   if (SFBChecksumEqual(cs,cs2)) println("same");  // Prints 'same'
 *   delay(1000);
 * }
 * \endcode
 */
int SFBChecksumFromString(SFBChecksum cs, const char * hexString);

#ifdef __cplusplus
}
#endif

#endif /* SFBCHECKSUM_H */
