Boost logo

Boost-Commit :

From: dwalker07_at_[hidden]
Date: 2008-08-21 04:05:55


Author: dlwalker
Date: 2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
New Revision: 48279
URL: http://svn.boost.org/trac/boost/changeset/48279

Log:
Added md5_byte_context, a variant of md5_context that woks byte-wise instead of bit-wise, and hopefully optimized; changed defintion of compute_md5 to use md5_byte_context; updated grouping & promotion header

Text files modified:
   sandbox/md5/boost/coding.hpp | 18 ++--
   sandbox/md5/boost/coding/md5.hpp | 15 ++--
   sandbox/md5/boost/coding/md5_context.hpp | 138 ++++++++++++++++++++++++++++++++++++++-
   sandbox/md5/boost/coding_fwd.hpp | 5
   sandbox/md5/libs/coding/src/md5.cpp | 37 ++++++++++
   sandbox/md5/libs/coding/test/md5_computer_test.cpp | 66 ++++++++++++++++++
   6 files changed, 253 insertions(+), 26 deletions(-)

Modified: sandbox/md5/boost/coding.hpp
==============================================================================
--- sandbox/md5/boost/coding.hpp (original)
+++ sandbox/md5/boost/coding.hpp 2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
@@ -1,17 +1,15 @@
 // Boost coding.hpp header file ---------------------------------------------//
-
-// (C) Copyright Daryle Walker 2008. Distributed under the Boost Software
-// License, Version 1.0. (See the accompanying file LICENSE_1_0.txt or a copy
-// at <http://www.boost.org/LICENSE_1_0.txt>.)
-
-// See <http://www.boost.org/libs/coding> for documentation.
-
 /** \file
- \brief Group-inclusion of Boost.Coding components
+ \brief Group-inclusion of Boost.Coding components.
 
     \#Includes all of the headers of Boost.Coding and promotes the public names
     to the main Boost namespace.
+
+ (C) Copyright Daryle Walker 2008. Distributed under the Boost Software
+ License, Version 1.0. (See the accompanying file LICENSE_1_0.txt or a copy
+ at <http://www.boost.org/LICENSE_1_0.txt>.)
  */
+// See <http://www.boost.org/libs/coding> for documentation.
 
 #ifndef BOOST_CODING_HPP
 #define BOOST_CODING_HPP
@@ -27,8 +25,10 @@
 
 // Namespace promotions ----------------------------------------------------//
 
-// From <boost/coding/md5.hpp>
+// Ultimately from <boost/coding/md5.hpp>
 using coding::md5_digest;
+using coding::md5_context;
+using coding::md5_byte_context;
 using coding::md5_computer;
 using coding::compute_md5;
 

Modified: sandbox/md5/boost/coding/md5.hpp
==============================================================================
--- sandbox/md5/boost/coding/md5.hpp (original)
+++ sandbox/md5/boost/coding/md5.hpp 2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
@@ -19,7 +19,7 @@
 
 #include <boost/coding_fwd.hpp>
 #include <boost/coding/md5_digest.hpp> // for boost::coding::md5_digest
-#include <boost/coding/md5_context.hpp> // for b:c:md5_context (for grouping)
+#include <boost/coding/md5_context.hpp> // for b:c:md5_(byte_)context
 #include <boost/coding/md5_computer.hpp> // for boost::coding::md5_computer
 
 #include <cstddef> // for std::size_t
@@ -48,15 +48,16 @@
     \return The MD5 message digest of the data block.
 
     \see boost::coding::md5_digest
- \see boost::coding::md5_computer
+ \see boost::coding::md5_byte_context
  */
-inline md5_digest
-compute_md5( void const *buffer, std::size_t byte_count )
+inline md5_digest compute_md5( void const *buffer, std::size_t byte_count )
 {
- md5_computer c;
+ md5_byte_context c;
+ unsigned char const * b = static_cast<unsigned char const *>( buffer );
 
- c.process_bytes( buffer, byte_count );
- return c.checksum();
+ while ( byte_count-- )
+ c( *b++ );
+ return c();
 }
 
 

Modified: sandbox/md5/boost/coding/md5_context.hpp
==============================================================================
--- sandbox/md5/boost/coding/md5_context.hpp (original)
+++ sandbox/md5/boost/coding/md5_context.hpp 2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
@@ -39,17 +39,31 @@
 #include <string> // for std::string
 
 
+// Control-macro definitions -----------------------------------------------//
+
+// Control macro for whole-byte processing
+#ifndef BOOST_CODING_MD5_CONTROL_OPTIMIZE_BYTE_ENTRY
+/** \brief Preprocessor control flag for optimized byte entry for MD5.
+
+ Indicates whether \c boost::coding::md5_byte_context should pass on bytes a
+ bit at a time or violate encapsulation by copying bytes whole into its inner
+ \c boost::coding::md5_context object. Even if active, the optimization will
+ not happen unless the bits-per-byte count, \c CHAR_BIT, is a factor of the
+ MD5 packed-bit array size (512 bits). If not overriden, it defaults to 1,
+ activating the optimization if possible.
+
+ \see boost::coding::md5_byte_context
+ */
+#define BOOST_CODING_MD5_CONTROL_OPTIMIZE_BYTE_ENTRY 1
+#endif
+
+
 namespace boost
 {
 namespace coding
 {
 
 
-// Forward declarations ----------------------------------------------------//
-
-// None right now
-
-
 // MD5 message-digest core computation class declaration -------------------//
 
 /** \brief A computer that produces MD5 message digests from consuming bits.
@@ -93,6 +107,7 @@
     product_type operator ()() const;//@}
 
 private:
+ friend class md5_byte_context;
     friend class md5_computer;
 
     // Implementation types and meta-constants
@@ -323,6 +338,119 @@
 }
 
 
+// MD5 message-digest byte-wise computation class declaration --------------//
+
+/** \brief A computer that produces MD5 message digests from consuming bytes.
+
+ This class is a variant of \c boost::coding::md5_context in that it consumes
+ values a byte at a time instead of bit-wise. It uses the same algorithm,
+ but can optimize entry if \c CHAR_BIT is a factor of the block size (512
+ bits). Besides computation, it also supports comparisons (equivalence only,
+ not ordering) and serialization.
+
+ \see boost::coding::md5_digest
+ \see boost::coding::md5_context
+ \see BOOST_CODING_MD5_CONTROL_OPTIMIZE_BYTE_ENTRY
+ */
+class md5_byte_context
+{
+ typedef md5_byte_context self_type;
+
+public:
+ // Types
+ /** \brief Type of the produced output
+
+ Represents the result type, the checksums from hashing.
+ */
+ typedef md5_digest product_type;
+ /** \brief Type of the consumed input
+
+ Represents the argument type, the data to hash.
+ */
+ typedef unsigned char consumed_type;
+
+ /*! \name Operators */ //@{
+ // Operators (use automatic copy-assignment)
+ //! Application, consumer
+ void operator ()( consumed_type byte );
+ //! Equals
+ bool operator ==( self_type const &o ) const;
+ //! Not-equals
+ bool operator !=( self_type const &o ) const;
+ //! Application, producer
+ product_type operator ()() const;//@}
+
+private:
+ // Member data
+ md5_context inner;
+
+ /*! \name Persistence */ //@{
+ // Serialization
+ friend class boost::serialization::access;
+
+ //! Enables persistence with Boost.Serialization-compatible archives
+ template < class Archive >
+ void serialize( Archive &ar, const unsigned int version );//@}
+
+}; // md5_byte_context
+
+
+// MD5 message-digest byte-wise computation class member func. defintions --//
+
+/** Compares computation contexts for equivalence. Such contexts are equal if
+ their internal states are equal. (This means that they should both return
+ the same checksum, and continue to do so as long as the same byte sequence
+ is submitted to both contexts.)
+
+ \param o The right-side operand to be compared.
+
+ \retval true \c *this and \p o are equivalent.
+ \retval false \c *this and \p o are not equivalent.
+ */
+inline bool md5_byte_context::operator ==( self_type const &o ) const
+{ return this->inner == o.inner; }
+
+/** Compares computation contexts for non-equivalence. Such engines are unequal
+ if their internal states are unequal. (Usually, the two contexts would
+ return checksums that differ either immediately or after the same byte
+ sequence is submitted to both contexts. However, it is possible for two
+ contexts with differing input histories to have the same output checksum.
+ Worse, it is possible to deliberately create such a collision.)
+
+ \param o The right-side operand to be compared.
+
+ \retval true \c *this and \p o are not equivalent.
+ \retval false \c *this and \p o are equivalent.
+ */
+inline bool md5_byte_context::operator !=( self_type const &o ) const
+{ return !this->operator ==( o ); }
+
+/** Provides the computed check-sum of all the submitted bytes (as if the
+ message is complete), through a standard generator interface.
+
+ \return The check-sum.
+ */
+inline md5_byte_context::product_type md5_byte_context::operator ()() const
+{ return this->inner(); }
+
+/** Streams a byte-wise core computer to/from an archive using the
+ Boost.Serialization protocols. This member function is meant to be called
+ only by the Boost.Serialization system, as needed.
+
+ \tparam Archive The type of \p ar. It must conform to the requirements
+ Boost.Serialization expects of archiving classes.
+
+ \param ar The archiving object that this object's representation will
+ be streamed to/from.
+ \param version The version of the persistence format for this object. (It
+ should be zero, since this type just got created.)
+ */
+template < class Archive >
+inline void
+md5_byte_context::serialize( Archive &ar, const unsigned int version )
+{ ar & BOOST_SERIALIZATION_NVP( inner ); }
+
+
 } // namespace coding
 } // namespace boost
 

Modified: sandbox/md5/boost/coding_fwd.hpp
==============================================================================
--- sandbox/md5/boost/coding_fwd.hpp (original)
+++ sandbox/md5/boost/coding_fwd.hpp 2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
@@ -50,19 +50,20 @@
 
 // From <boost/coding/md5_digest.hpp> --------------------------------------//
 
-// Only has operator free-functions, #includes "md5_digest_core.hpp"
+// Has operator and support free-functions, #includes "md5_digest_core.hpp"
 
 
 // From <boost/coding/md5_context.hpp> -------------------------------------//
 
 class md5_context;
+class md5_byte_context;
 
 
 // From <boost/coding/md5_computer.hpp> ------------------------------------//
 
 class md5_computer;
 
-// Also has a support free-function
+// Has support free-functions
 
 
 // From <boost/coding/md5.hpp> ---------------------------------------------//

Modified: sandbox/md5/libs/coding/src/md5.cpp
==============================================================================
--- sandbox/md5/libs/coding/src/md5.cpp (original)
+++ sandbox/md5/libs/coding/src/md5.cpp 2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
@@ -26,6 +26,7 @@
 #include <boost/detail/endian.hpp> // for BOOST_LITTLE_ENDIAN
 #include <boost/integer/integer_mask.hpp> // for boost::integer_lo_mask
 #include <boost/math/common_factor_rt.hpp> // for boost::math::gcd
+#include <boost/mpl/assert.hpp> // for BOOST_MPL_ASSERT_RELATION
 #include <boost/typeof/typeof.hpp> // for BOOST_AUTO
 
 #include <algorithm> // for std::copy, fill
@@ -320,7 +321,8 @@
     // High-order-bit-first is also how the bit-oriented MD5 algorithm reads a
     // byte. There is a bonus that an optimized byte-consumption routine can
     // copy a byte directly into the array for quick entry, at least if CHAR_BIT
- // divides index.
+ // divides index. See md5_byte_context::operator()(unsigned char) for the
+ // optimized byte-entry code.
 
     if ( bit ) byte |= mask;
     else byte &= ~mask;
@@ -570,6 +572,39 @@
 }
 
 
+// MD5 message-digest byte-wise computation non-inline member definitions --//
+
+/** Submits a byte for processing.
+
+ \param byte The byte value to be submitted.
+
+ \post Sorry, there is no externally-accessible state. (However, the byte
+ is queued until enough have been collected to update the internal
+ hash. If an update occurs, the queue is emptied.)
+ */
+void md5_byte_context::operator ()( consumed_type byte )
+{
+#if (512 % CHAR_BIT == 0) && BOOST_CODING_MD5_CONTROL_OPTIMIZE_BYTE_ENTRY
+ // Copy the byte in whole. It is already compatible with the format of the
+ // packed-bit array's packing. Since the inner md5_context's entry checking
+ // is skipped, we have to redo the logic of md5_context::consume_bit here.
+ BOOST_MPL_ASSERT_RELATION( md5_context::bits_per_block::value, ==, 512 );
+ int const index = this->inner.length % md5_context::bits_per_block::value;
+ int const byte_index = index / CHAR_BIT;
+
+ BOOST_ASSERT( index % CHAR_BIT == 0 );
+ this->inner.queue[ byte_index ] = byte;
+ this->inner.length += CHAR_BIT;
+ if ( index + CHAR_BIT == md5_context::bits_per_block::value )
+ this->inner.update_hash();
+#else
+ // Enter each bit in the offical order (highest-order first)
+ for ( unsigned char m = 1u << (CHAR_BIT - 1) ; m ; m >>= 1 )
+ this->inner( byte & m );
+#endif
+}
+
+
 // MD5 message-digest computation non-inline member definitions ------------//
 
 /** Sample of the table described in RFC 1321, section 3.4, paragraph 4. Its

Modified: sandbox/md5/libs/coding/test/md5_computer_test.cpp
==============================================================================
--- sandbox/md5/libs/coding/test/md5_computer_test.cpp (original)
+++ sandbox/md5/libs/coding/test/md5_computer_test.cpp 2008-08-21 04:05:53 EDT (Thu, 21 Aug 2008)
@@ -40,13 +40,12 @@
 #define PRIVATE_SHOW_MESSAGE( m ) BOOST_TEST_MESSAGE( m )
 #endif
 
-BOOST_TEST_DONT_PRINT_LOG_VALUE( boost::coding::md5_computer );
-
 
 #pragma mark Intro stuff
 
 // Put any using-ed types & templates, and typedefs here
 using boost::array;
+using boost::coding::md5_byte_context;
 using boost::coding::md5_computer;
 using boost::coding::md5_digest;
 
@@ -91,6 +90,8 @@
 
 
 // Mark any unprintable tested types here
+BOOST_TEST_DONT_PRINT_LOG_VALUE( boost::coding::md5_byte_context );
+BOOST_TEST_DONT_PRINT_LOG_VALUE( boost::coding::md5_computer );
 
 
 #pragma mark -
@@ -691,13 +692,74 @@
     BOOST_CHECK_NE( test, c2 );
 }
 
+// Byte-optimized MD5-context object tests
+BOOST_AUTO_TEST_CASE( md5_byte_context_test )
+{
+ using boost::coding::md5_byte_context;
+ using boost::coding::md5_context;
+
+ // Default construction and production
+ md5_byte_context const c1;
+ md5_computer scratch;
+
+ BOOST_CHECK_EQUAL( c1(), scratch.context()() );
+
+ // Equality
+ md5_byte_context c2;
+
+ BOOST_CHECK( c1 == c2 );
+ BOOST_CHECK( !(c2 != c1) );
+
+ // Consumption
+ unsigned char const test_value = 0x02u;
+
+ c2( test_value );
+ scratch.process_byte( test_value );
+ BOOST_CHECK_EQUAL( c2(), scratch.context()() );
+
+ // Inequality
+ BOOST_CHECK( c1 != c2 );
+ BOOST_CHECK( !(c2 == c1) );
+
+ // Copy construction
+ md5_byte_context test( c2 );
+
+ BOOST_CHECK_EQUAL( test, c2 );
+ BOOST_REQUIRE_NE( test, c1 );
+
+ // More consumption, but make sure the hash queue turns over
+ int const test_length = 512 / CHAR_BIT + !!(512 % CHAR_BIT);
+
+ for ( int i = test_length ; i ; --i )
+ c2( test_value );
+ scratch.process_byte_copies( test_value, test_length );
+ BOOST_CHECK_EQUAL( c2(), scratch.checksum() );
+
+ // Quick S11N check
+ std::stringstream ss;
+
+ write_xml_archive( ss, c1, "test" );
+ PRIVATE_SHOW_MESSAGE( ss.str() );
+ read_xml_archive( ss, test, "test" );
+ BOOST_CHECK_EQUAL( test, c1 );
+ BOOST_CHECK_NE( test, c2 );
+}
+
 // Single-call function test
 BOOST_AUTO_TEST_CASE( compute_md5_test )
 {
     using boost::coding::compute_md5;
 
+ // Empty check
     BOOST_CHECK_EQUAL( compute_md5(0, 0), md5_empty_data );
 
+ // Check against another component
+ unsigned char const test_value = 0x6Fu;
+ md5_computer scratch;
+
+ scratch.process_byte( test_value );
+ BOOST_CHECK_EQUAL( compute_md5(&test_value, 1u), scratch.checksum() );
+
     // How do we get consistent data when we can't count on CHAR_BIT being the
     // same everywhere? Do we just screw over testers without 8-bit bytes or
     // ones without ASCII (or superset)? If so, then we could use the other


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk