Sans Pareil Technologies, Inc.

Key To Your Business

Checksum



Checksum with CRC32 and Adler32 based algorithms. The interface is from Poco, but the implementations are from searches for Arduino compatibility. The Poco implementation is based on zlib, which is too large to fit on Arduino (requires a lot more SRAM than available).

Checksum.h

Definition of the checksum interface.

    1: /*
    2: * Checksum.h
    3: *
    4: * Definition of the Checksum class.
    5: *
    6: * Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
    7: * and Contributors.
    8: *
    9: * Permission is hereby granted, free of charge, to any person or organization
   10: * obtaining a copy of the software and accompanying documentation covered by
   11: * this license (the "Software") to use, reproduce, display, distribute,
   12: * execute, and transmit the Software, and to prepare derivative works of the
   13: * Software, and to permit third-parties to whom the Software is furnished to
   14: * do so, all subject to the following:
   15: *
   16: * The copyright notices in the Software and this entire statement, including
   17: * the above license grant, this restriction and the following disclaimer,
   18: * must be included in all copies of the Software, in whole or in part, and
   19: * all derivative works of the Software, unless such copies or derivative
   20: * works are solely in the form of machine-executable object code generated by
   21: * a source language processor.
   22: *
   23: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   24: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   25: * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
   26: * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
   27: * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
   28: * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   29: * DEALINGS IN THE SOFTWARE.
   30: */
   31:
   32:
   33: #ifndef SPT_CHECKSUM
   34: #define SPT_CHECKSUM
   35:
   36: #if defined( ARDUINO )
   37: #include "../StandardCplusplus/string"
   38: #else
   39: #include <string>
   40: #endif
   41:
   42: namespace spt
   43: {
   44:   /// @brief This class calculates CRC-32 or Adler-32 checksums for arbitrary data.
   45:   ///
   46:   /// A cyclic redundancy check (CRC) is a type of hash function, which is used to produce a
   47:   /// small, fixed-size checksum of a larger block of data, such as a packet of network
   48:   /// traffic or a computer file. CRC-32 is one of the most commonly used CRC algorithms.
   49:   ///
   50:   /// Adler-32 is a checksum algorithm which was invented by Mark Adler.
   51:   /// It is almost as reliable as a 32-bit cyclic redundancy check for protecting against
   52:   /// accidental modification of data, such as distortions occurring during a transmission,
   53:   /// but is significantly faster to calculate in software.
   54:   class Checksum
   55:   {
   56:   public:
   57:     enum Type
   58:     {
   59:       TYPE_ADLER32 = 0,
   60:       TYPE_CRC32
   61:     };
   62:
   63:     /// Creates the Checksum, using the given type initialised to 0.
   64:     Checksum( Type t = TYPE_CRC32 );
   65:
   66:     /// Destroys the Checksum.
   67:     ~Checksum() {}
   68:
   69:     /// Updates the checksum with the given data.
   70:     void update( const char* data, uint16_t length );
   71:
   72:     /// Updates the checksum with the given data.
   73:     void update( const std::string& data )
   74:     {
   75:       update( data.c_str(), static_cast<uint32_t>( data.size() ) );
   76:     }
   77:
   78:     /// Updates the checksum with the given data.
   79:     void update( char data ) { update( &data, 1 ); }
   80:
   81:     /// Returns the calculated checksum.
   82:     uint32_t checksum() const { return value; }
   83:
   84:     /// Which type of checksum are we calulcating
   85:     Type getType() const { return type; }
   86:
   87:   private:
   88:     Type type;
   89:     uint32_t value;
   90:   };
   91:
   92: } // namespace spt
   93:
   94:
   95: #endif // SPT_CHECKSUM


Checksum.cpp

Implementation of the checksum algorithms.

    1: /*
    2: * Checksum.cpp
    3: *
    4: * Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
    5: * and Contributors.
    6: *
    7: * Permission is hereby granted, free of charge, to any person or organization
    8: * obtaining a copy of the software and accompanying documentation covered by
    9: * this license (the "Software") to use, reproduce, display, distribute,
   10: * execute, and transmit the Software, and to prepare derivative works of the
   11: * Software, and to permit third-parties to whom the Software is furnished to
   12: * do so, all subject to the following:
   13: *
   14: * The copyright notices in the Software and this entire statement, including
   15: * the above license grant, this restriction and the following disclaimer,
   16: * must be included in all copies of the Software, in whole or in part, and
   17: * all derivative works of the Software, unless such copies or derivative
   18: * works are solely in the form of machine-executable object code generated by
   19: * a source language processor.
   20: *
   21: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   22: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   23: * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
   24: * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
   25: * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
   26: * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   27: * DEALINGS IN THE SOFTWARE.
   28: */
   29:
   30:
   31: #include "Checksum.h"
   32: #include "SPT.h"
   33:
   34: namespace spt
   35: {
   36:   namespace checksum
   37:   {
   38:     const uint32_t Polynomial = 0xEDB88320;
   39:     #define BASE 65521 /* largest prime smaller than 65536 */
   40:
   41:     uint32_t adler32( const Byte *buf, uint16_t len, uint32_t previousAdler = 1 )
   42:     {
   43:       uint32_t s1 = previousAdler & 0xffff;
   44:       uint32_t s2 = ( previousAdler >> 16 ) & 0xffff;
   45:
   46:       for ( uint16_t n = 0; n < len; ++n )
   47:       {
   48:         s1 = ( s1 + buf[n] ) % BASE;
   49:         s2 = ( s2 + s1 ) % BASE;
   50:       }
   51:
   52:       return ( s2 << 16 ) + s1;
   53:     }
   54:
   55:     /// compute CRC32
   56:     uint32_t crc32( const Byte* data, uint16_t length, uint32_t previousCrc32 = 0 )
   57:     {
   58:       uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF
   59:       uint8_t* current = (uint8_t*) data;
   60:
   61:       while ( length-- )
   62:       {
   63:         crc ^= *current++;
   64:         for ( uint8_t j = 0; j < 8; ++j )
   65:         {
   66:           uint8_t lowestBit = crc & 1;
   67:           crc >>= 1;
   68:           if ( lowestBit ) crc ^= Polynomial;
   69:         }
   70:       }
   71:
   72:       return ~crc; // same as crc ^ 0xFFFFFFFF
   73:     }
   74:
   75:   } // namespace checksum
   76: } // namespace spt
   77:
   78:
   79: using spt::Byte;
   80: using spt::Checksum;
   81:
   82:
   83: Checksum::Checksum( Type t ) : type( t ), value( 0 )
   84: {
   85:   if ( t == TYPE_ADLER32 ) value = 1;
   86: }
   87:
   88:
   89: void Checksum::update(const char* data, uint16_t length )
   90: {
   91:   if ( type == TYPE_ADLER32 ) value = spt::checksum::adler32( reinterpret_cast<const Byte*>( data ), length, value );
   92:   else value = spt::checksum::crc32( reinterpret_cast<const Byte*>( data ), length, value );
   93: }


ChecksumTest.cpp

Unit test suite for the checksum computations.

    1: #if defined( ARDUINO )
    2: #include "tut.hpp"
    3: #include "SPT.h"
    4: #include "Checksum.h"
    5: #else
    6: #include <tut/tut.hpp>
    7: #include <Checksum.h>
    8: #include <SPT.h>
    9: #endif
   10:
   11: using spt::Checksum;
   12: using std::string;
   13:
   14: namespace tut
   15: {
   16:   struct ChecksumTestData {};
   17:
   18:   typedef test_group<ChecksumTestData> ChecksumTestGroup;
   19:   typedef ChecksumTestGroup::object ChecksumTest;
   20:   ChecksumTestGroup checksumTestGroup( "Checksum test suite" );
   21:
   22:
   23:   template<>
   24:   template<>
   25:   void ChecksumTest::test<1>()
   26:   {
   27:     set_test_name( "abc" );
   28:
   29:     string s( "abc" );
   30:     Checksum cs;
   31:     cs.update( s );
   32:     ensure( "abc", cs.checksum() == 891568578 );
   33:     spt::printFreeRam();
   34:   }
   35:
   36:
   37:   template<>
   38:   template<>
   39:   void ChecksumTest::test<2>()
   40:   {
   41:     set_test_name( "lower case" );
   42:
   43:     string s( "abcdefghijklmnopqrstuvwxyz" );
   44:     Checksum cs;
   45:     cs.update( s );
   46:     ensure( "lower case", cs.checksum() == 1277644989 );
   47:     spt::printFreeRam();
   48:   }
   49:
   50:
   51:   template<>
   52:   template<>
   53:   void ChecksumTest::test<3>()
   54:   {
   55:     set_test_name( "upper case" );
   56:
   57:     string s( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
   58:     Checksum cs;
   59:     cs.update( s );
   60:     ensure( "upper case", cs.checksum() == 2885122082 );
   61:     spt::printFreeRam();
   62:   }
   63:
   64:
   65:   template<>
   66:   template<>
   67:   void ChecksumTest::test<4>()
   68:   {
   69:     set_test_name( "numbers and characters" );
   70:
   71:     string s( "ABCDEFGHIJKL12345678901234567890123456789012345678901234567890123456789012345678901234567890MNOPQRSTUVWXYZ" );
   72:     Checksum cs;
   73:     cs.update( s );
   74:     ensure( "numbers and characters", cs.checksum() == 1170154626 );
   75:     spt::printFreeRam();
   76:   }
   77:
   78:
   79:   template<>
   80:   template<>
   81:   void ChecksumTest::test<5>()
   82:   {
   83:     set_test_name( "adler" );
   84:
   85:     string s( "ABCDEFGHIJKL12345678901234567890123456789012345678901234567890123456789012345678901234567890MNOPQRSTUVWXYZ" );
   86:     Checksum cs( Checksum::TYPE_ADLER32 );
   87:     cs.update( s );
   88:     ensure( "adler", cs.checksum() == 3934918728 );
   89:     spt::printFreeRam();
   90:   }
   91:
   92:
   93:   template<>
   94:   template<>
   95:   void ChecksumTest::test<6>()
   96:   {
   97:     set_test_name( "crcUpdates" );
   98:
   99:     Checksum cs;
  100:     cs.update( 'a' );
  101:     cs.update( 'b' );
  102:     cs.update( 'c' );
  103:     ensure( "crcUpdates", cs.checksum() == 0x352441C2 );
  104:     spt::printFreeRam();
  105:   }
  106:
  107:
  108:   template<>
  109:   template<>
  110:   void ChecksumTest::test<7>()
  111:   {
  112:     set_test_name( "adlerUpdates" );
  113:
  114:     Checksum cs( Checksum::TYPE_ADLER32 );
  115:     cs.update( 'a' );
  116:     cs.update( 'b' );
  117:     cs.update( 'c' );
  118:     ensure( "adlerUpdates", cs.checksum() == 0x024D0127 );
  119:     spt::printFreeRam();
  120:   }
  121: }