OSDN Git Service

Implemented "flip-{1,2}" and "flip-N" optimization methods.
[mhash384/mhash384.git] / README.md
index 318a664..6a48d1b 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,12 +1,23 @@
-% MHash-384
+% ![](img/mhash/MHash-384.jpg)  
+MHash-384
 % Simple fast portable header-only hashing library
 
+# Introduction
+
+**MHash-384** is a fast, portable and secure *header-only* hash library, released under the *MIT license*. It provides a very simple "stream processing" API and produces hash values with a length of 384 bits (48 bytes).
+
+The MHash-384 library has originally been written for **C** and **C++**. It provides a "plain C" API as well as an *object-oriented* C++ wrapper. It also supports many compilers (MSVC, GCC, MinGW, etc.) on various platforms (Windows, Linux, etc).
+
+Furthermore, the MHash-384 library has already been *ported* to various other programming languages. This currently includes the **Microsoft.NET** platform (C#, VB.NET, etc.), **Java**, **Delphi** (Pascal) as well as **Python**.
+
 
 # Quick Start Guide
 
-In order to use the *MHash-384* library, simply include the header file in your *C* or *C++* source code file; linking any additional library files to your program is **not** required.
+In order to use the *MHash-384* library, simply include the header file `mhash_384.h` in your *C* or *C++* source code file.
 
-       #include "mhash_384.h"
+This is the *only* file you are going to need. Being a [*header-only*](https://en.wikipedia.org/wiki/Header-only) library, MHash-384 does **not** require any additional library files to be linked to your program. Also, **no** additional DLL files (or *shared objects*) are required at runtime.
+
+       #include <mhash_384.h>
 
 ## Example for C language
 
@@ -40,12 +51,12 @@ And, if you source code is written in **C++**, the *MHash384* class from *mhash*
        uint8_t result[MHASH_384_LEN];
        
        /*construction*/
-       mhash::MHash384 instance;
+       mhash_384::MHash384 instance;
        
        /*input data processing*/
-       while(have_more_data())
+       while(source.have_more_data())
        {
-               data = fetch_next_data_chunk();
+               data = source.fetch_next_data_chunk();
                instance.update(data);
        }
        
@@ -55,11 +66,11 @@ And, if you source code is written in **C++**, the *MHash384* class from *mhash*
 
 # Command-line Usage
 
-MHash-384 comes with a simple "standalone" command-line application. This program primarily serves as an example on how to use the MHash-384 library. However, the command-line application may also come in handy to quickly compute MHash-384 checksums (hashes) of local files. Furthermore, the MHash-384 program integrates nicely into the "pipes and filters" design pattern, by processing arbitrary inputs from the standard input stream. Computed checksums (hashes) will be written to the standard output stream, as a Hex string.
+MHash-384 comes with a simple "standalone" command-line application. This program primarily serves as an example on how to use the library. However, the command-line application may also come in handy to quickly compute checksums (hashes) of local files. Furthermore, the MHash-384 program integrates nicely into the "pipes and filters" design pattern, by consuming arbitrary inputs from the standard input stream and writing hash values (as Hex string) to the standard output stream.
 
 ## Synopsis
 
-MHash-384 takes a number of optional options followed by an optional input file. If **no** input file is specified, or if input file is "-", input will be read from standard input stream (*stdin*).
+The MHash-384 command-line application takes a number of optional options followed by an optional input file. If **no** input file is specified, or if input file is "-", input will be read from standard input stream (*stdin*).
 
        mhash_384 [options] [input_file]
 
@@ -67,23 +78,23 @@ MHash-384 takes a number of optional options followed by an optional input file.
 
 MHash-384 supports the following options:
 
-* `-p`, `--progress`  
+* **`-p`**, **`--progress`**  
   Print the total size of the input file and the percentage processed so far to *stderr* while hash computation is running.  
   If the total input size can **not** be determined (e.g. using pipe), the number of bytes processed so far is printed.
 
-* `-u`, `--upper`  
+* **`-u`**, **`--upper`**  
   Output the final digest (hash) in *upper case* Hex letters. Default mode is *lower case*.
 
-* `-b`, `--bench`  
+* **`-b`**, **`--bench`**  
   Compute performance statistics (e.g. bytes processed per second) and print them to the *stderr* at the end of the process.
 
-* `-v`, `--version`  
+* **`-v`**, **`--version`**  
   Print library version to the *stdout* and exit program.
 
-* `-t`, `--test`  
+* **`-t`**, **`--test`**  
   Run *built-in self-test* and exit program. Computes hashes from test vectors and compares results to reference hashes.
 
-* `-h`, `--help`  
+* **`-h`**, **`--help`**  
   Print help screen (man page) and exit program.
 
 ## Examples
@@ -92,11 +103,75 @@ Compute MHash-384 hash of a local file:
 
        mhash_384 C:\Images\debian-8.3.0-amd64-DVD-1.iso"
 
+Compute MHash-384 hash of a local file, with more verbose status outputs:
+
+       mhash_384 -p -b C:\Images\debian-8.3.0-amd64-DVD-1.iso"
+
 Compute MHash-384 from random bytes, passing data directly from [`dd`](https://en.wikipedia.org/wiki/Dd_%28Unix%29) via pipe:
 
        dd if=/dev/urandom bs=100 count=1 | mhash_384
 
 
+# Algoritm Description
+
+This chapter describes the MHash-384 algorithm, as designed &ndash; from the scratch &ndash; by LoRd_MuldeR &lt;mulder2@gmx.de&gt;.
+
+## Informal Description
+
+MHash-384 uses a table of *257* pre-computed 384-Bit words. This table is referred to as the *XOR-table*. It has been generated in such a way that each possible pair of 384-Bit words has a binary [Hamming distance](https://en.wikipedia.org/wiki/Hamming_distance) of *at least* 180 bits.
+
+The MHash-384 digest of a given input message is computed in a *stream-like* fashion. This means that we start with the "empty" (zero) hash value, we will process the given message *byte by byte*, and we will "update" the hash value for each input byte. The final hash value of a message is the hash value that results after all of its bytes have been processed.
+
+The "update" rule is defined as follows: We select the 384-Bit word from the XOR-table whose index matches the current input byte value, and we *combine* the selected 384-Bit word with the previous hash value in order to form the new (updated) hash value. If, for example, the current input byte equals `0x00`, then we select the *first* 384-Bit word from the XOR-table. If the current input byte equals `0x01`, then we select the *second* 384-Bit word from the XOR-table. And so on&hellip;
+
+In any case, the selected 384-Bit word (from the XOR-table) will be combined with the previous hash value using the binary [XOR](https://en.wikipedia.org/wiki/Exclusive_or) (exclusive OR) function. XOR'ing the previous hash value with the selected 384-Bit word will effectively *flip* a certain sub-set of its bits &ndash; depending on the current input byte value. Because the 384-Bit words in the XOR-table have a guaranteed minimum Hamming distance to each other, each possible input byte value is also guaranteed to flip a *different* subset of bits.
+
+In fact the "update" rule is slightly more complex. That's because, in each update step, the previous hash value bytes additionally will be *shuffled* (permuted). The shuffling of the hash bytes will be performed immediately *before* XOR'ing the previous hash value with the select 384-Bit word from the XOR-table. Be aware that the shuffling ensures that the *same* input bytes are going results in a *different* hash value &ndash; with very high probability &ndash; when they are processed in a different order.
+
+The shuffling procedure is implemented using the [Fisher-Yates](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) "in-place" shuffle algorithm. For this purpose, MHash-384 uses a table of *997* pre-computed permutations. This table is referred to as the *MIX-table*. Each of its rows (permutations) contains 48 Fisher-Yates shuffling indices, as required to shuffle the 48 hash bytes. The MIX-table has been generated in such a way, that each of the *997* permutations "moves" the elements (hash bytes) to different positions than all other permutations.
+
+We use a counter that keeps track of the MIX-table row (permutation). The counter's value equals the zero-based index of the MIX-table row which is to be applied in the *next* update step. It is initialized to *zero* at the beginning, and it will be increased by one after each update step. After the *last* MIX-table row (i.e. index *996*) the counter will wrap around to index *zero* again.
+
+Last but not least, the computation of the MHash-384 digest is *finalized* by XOR'ing the current hash value with the very last 384-Bit word of the XOR-table. This 384-Bit word has index 256 and therefore can *never* be selected by any input byte value.
+
+## Pseudocode
+
+The MHash-384 algorithm can be summed up with the following simple pseudocode:
+
+       procedure mhash384
+       const:
+         HASH_SIZE = 48
+         TABLE_XOR: array[257 × HASH_SIZE] of byte
+         TABLE_MIX: array[997 × HASH_SIZE] of byte
+       input:
+         message: array[N] of byte
+       output:
+         hash: array[HASH_SIZE] of byte
+       vars:
+         round: integer
+       begin
+         /*initialization*/
+         round ← 0
+         for i = 0 to HASH_SIZE-1 do
+           hash[i] ← 0x00
+         done
+         
+         /*input message processing*/
+         for k = 0 to N-1 do
+           for i = 0 to HASH_SIZE-1 do
+             exchange hash[i] ⇄ hash[TABLE_MIX[round][i]]
+             hash[i] ← hash[i] ⊕ TABLE_XOR[message[k]][i]
+           done
+           round ← (round + 1) mod 997
+         done
+         
+         /*finalization*/
+         for i = 0 to HASH_SIZE-1 do
+           hash[i] ← hash[i] ⊕ TABLE_XOR[256][i]
+         done
+       end.
+
+
 # Detailed API Specification
 
 Global definitions for both, C and C++, API's.
@@ -273,15 +348,202 @@ This method is used to finalize the hash computation and output the final digest
 
 MHash-384 library should compile on any standard-compliant C/C++ compiler. In particular, the following platforms have been tested successfully:
 
-* GNU/Linux, using GCC/G++, version 4.7 or later
 * Microsoft Windows
-    - Microsoft C/C++ Compiler, Visual Studio 2010 or later
+    - Microsoft C/C++ Compiler, using Visual Studio 2010 or later
     - MinGW, using Mingw-w64 from [MSYS2](https://msys2.github.io/) project
 * Intel C/C++ Compiler, version Version 15.0 (XE 2015) or later
+* GNU/Linux, using GCC/G++, version 4.7 or later
+
+# Language Bindings
+
+While the MHash-384 library is primarily targeted for C/C++ applications, *language bindings* are provided for a variety of programming languages. This allows for using the MHash-384 library in pretty much any scenario/environment.
+
+## Microsoft.NET
+
+Bindings of the MHash-384 library are provided for **Microsoft.NET**, in the form of a [*C++/CLI*](https://en.wikipedia.org/wiki/C%2B%2B/CLI) assembly file.
+
+In order to use the MHash-384 library in your Microsoft.NET (e.g. C# or VB.NET) application, simply instantiate the `MHash384` convenience class from the `MHashDotNet` package:
+
+       using MHashDotNet;
+
+       byte[] ComputeHash(FileStream fs)
+       {
+               byte[] buffer = new byte[4096];
+               using (MHash384 digest = new MHash384())
+               {
+                       while (true)
+                       {
+                               int count = fs.Read(buffer, 0, buffer.Length);
+                               if (count > 0)
+                               {
+                                       digest.Update(buffer, 0, count);
+                                       continue;
+                               }
+                               break;
+                       }
+                       return digest.GetResult();
+                }
+       }
+
+***Note:*** The `MHash384` class is designed to be used via C#'s [`using`](http://www.dotnetperls.com/using) statement (or VB.NET's `Using...` block). This will ensure that "native" resources are *always* cleaned up!
+
+### Prerequisites
+
+In order to use the MHash-384 library in your Microsoft.NET (e.g. C# or VB.NET) application, a reference to the `MHashDotNet384.x86.dll` or `MHashDotNet384.x64.dll` assembly must be added to the project.
+
+***Note:*** The *32-Bit* (x86) CLR can only work with the `MHashDotNet384.x86.dll` assembly, and the *64-Bit* (x64) CLR can only work with the `MHashDotNet384.x64.dll` assembly!
+
+## Java
+
+Bindings of the MHash-384 library are provided for **Java**, in the form of a [*JNI*](https://en.wikipedia.org/wiki/Java_Native_Interface) (Java Native Interface) module.
+
+In order to use the MHash-384 library in your Java application, simply import the `MHash384` convenience class from the `mhash` package:
+
+       import mhash.MHash384;
+       
+       byte[] computeHash(final InputStream inputStream) throws IOException {
+               final byte[] buffer = new byte[4096];
+               int count;
+               try(final MHash384 digest = new MHash384()) {
+                       do {
+                               count = inputStream.read(buffer);
+                               if(count > 0) {
+                                       digest.update(buffer, 0, count);
+                               }
+                       }
+                       while(count == buffer.length);
+                       return digest.result();
+               }
+       }
+
+***Note:*** The `MHash384` class is designed to be used via Javas's [`try-with-resources`](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html) statement. This will ensure that "native" resources are *always* cleaned up!
+
+### Prerequisites
+
+In order to use the MHash-384 library in your Java project, the JAR file 'MHashJava384-Wrapper.jar' must be added to the Java *build path*. Furthermore, the "native" library must be made available to the JVM *at runtime*. By default, the JVM will look for `MHashJava384.x86` or `MHashJava384.x64` in the `java.library.path` directory. You can overwrite the library name (without extension!) via the `mhash384.library.name` property, or you can specify the *full  path* of the library (including extension!) via the `mhash384.library.path` property.
+
+***Note:*** The *32-Bit* (x86) JVM can only work with the `MHashJava384.x86` library, and the *64-Bit* (x64) JVM can only work with the `MHashJava384.x64` library. Unless you specify the *full path*, the JVM will append a *platform-specific* file extension (`.dll` on Windows, `.so` on Linux).
+
+## Python
+
+Bindings of the MHash-384 library are provided for [**CPython**](https://en.wikipedia.org/wiki/CPython), in the form of an *extension module* (Python C/C++ API).
+
+In order to use the MHash-384 library in your Python application, simply import the `MHash384` convenience class from the `MHashPy384_Wrapper` module:
+
+       from MHashPy384_Wrapper import MHash384
+       
+       with MHash384() as digest:
+               for chunk in read_chunks():
+                       digest.update(chunk)
+               print(binascii.hexlify(digest.result()))
+
+***Note:*** The `MHash384` class is designed to be used via Python's [`with`](http://effbot.org/zone/python-with-statement.htm) statement. This will ensure that "native" resources are *always* cleaned up!
+
+### Prerequisites
+
+It is highly recommended to install the MHash-384 library into Python's [`site-packages`](https://docs.python.org/3.5/install/#how-installation-works) directory. For this purpose, create a new sub-directory `mhash` inside the `site-packages` directory. Then copy `mhash.pth` directly to the `site-packages` directory, so *site* will include the new sub-directory. Also, copy both modules, `MHashPy384_Wrapper.py` *and* `MHashPy384_Native.{pyd,so}`, to the `site-packages\mhash` sub-directory. The former module contains the `MHash384` convenience class, the latter module contains the "native" MHash-384 functions.
+
+***Note #1:*** The *32-Bit* (x86) version of Python can only work with the `MHashPy384_Native.x86` module, and the *64-Bit* (x64) version of Python can only work with the `MHashPy384_Native.x64` module.
+
+***Note #2:*** In any case, the "native" module **must** be renamed to just `MHashPy384_Native.pyd` or `MHashPy384_Native.so` when running on the Windows or Linux platform, respectively. Otherwise Python will *not* be able to locate the module!
+
+## Delphi
+
+Bindings of the MHash-384 library are provided for **Delphi** in the form of a "native" DLL. Tested with Borland Delphi 7.
+
+In order to use the MHash-384 library in your Delphi application, simply add the `MHash384` unit to the *uses* clause and instantiate the `TMHash384` convenience class:
+
+       uses
+               {...}, MHash384;
+       
+       function ComputeHash(var inputFile: File): TByteArray;
+       var
+               digest: TMHash384;
+               buffer: TByteArray;
+               count: Integer;
+       begin
+               SetLength(buffer, 4096);
+               digest := TMHash384.Create();
+               try
+                       while not Eof(inputFile) do
+                       begin
+                               BlockRead(inputFile, buffer[0], Length(buffer), count);
+                               if count > 0 then
+                               begin
+                                       digest.Update(buffer, 0, count);
+                               end;
+                       end;
+                       digest.Result(Result);
+               finally
+                       digest.Destroy();
+               end;
+       end;
+
+***Note:*** The `TMHash384` class should be used with a `try...finally` block and the destructor `TMHash384.Destroy` should be called in the `finally` section. This will ensure that "native" resources are *always* cleaned up!
+
+### Prerequisites
+
+In order to use the MHash-384 library in your Delphi application, the Unit file 'MHash384.pas' must be added to the project. This unit contains the `TMHash384` convenience class and associated data types. Furthermore, the "native" library `MHashDelphi384.dll` must be made available to the application *at runtime*. This DLL file contains the actual implementation. Simply copy the DLL to the same directory where the EXE file is located. Alternatively, the DLL can be located in the "System" directory or in any of directories in the `PATH` environment variable.
+
+***Note:*** *32-Bit* (x86) Delphi applications can only work with the `MHashDelphi384.x86.dll` library, and *64-Bit* (x64) Delphi applications can only work with the `MHashDelphi384.x64.dll` library!
+
+
+# Source Code
+
+The MHash-384 source is available from the official [**git**](https://git-scm.com/) mirrors:
+
+* `git clone https://github.com/lordmulder/mhash-384.git` [[Browse](https://github.com/lordmulder/mhash-384)]
+
+* `git clone https://bitbucket.org/muldersoft/mhash-384.git` [[Browse](https://bitbucket.org/muldersoft/mhash-384)]
+
+* `git clone https://git.assembla.com/mhash-384.git` [[Browse](https://www.assembla.com/spaces/mhash-384/git/source)]
+
+* `git clone https://gitlab.com/lord_mulder/mhash-384.git` [[Browse](https://gitlab.com/lord_mulder/mhash-384)]
+
+
+# Build Instructions
+
+This section describes how to build the MHash-384 sample application. Please note that you do **not** need to "build" the library in order to use it in your own application.
+
+* For supported versions of *Microsoft Visual Studio*, MHash-384 library ships with project/solution files, which will compile "out of the box".
+
+* The *Intel C/C++ Compiler* integrates into Visual Studio, so simply select "Use Intel C++" from the project/solution menu.
+
+* Optionally, the build script `Make.cmd` may be used to create ready-to-use deployment packages. Note, however, that it may be necessary to adjust the paths in the header section of the script!
+
+* Finally, for the *GNU/Linux* and *MinGW/MSYS2* platforms, the MHash-384 library provides a Makefile (tested with GNU Make). Just run `make` from the MHash-384 directory.
+
+## Influential Environment Variables
+
+The following environment variables may effect the build process and need to be set carefully:
+
+* **Java:**
+    - `JAVA_HOME`: The *Java* "home" directory, should be pointing to JDK (*not* JRE) root directory
+    - `ANT_HOME`: The *Apache Ant* "home" directory, should be pointing to root directory  
+
+* **Python:**
+    - `PYTHON_INC`: Directory to look for Python *include* files (typically `<PYTHON_INSTALL_PATH>/include`)
+    - `PYTHON_LIB32`: Directory to look for 32-Bit (x86) Python *library* files (typically `<PYTHON_X86_PATH>/libs`)
+    - `PYTHON_LIB64`: Directory to look for 64-Bit (x64) Python *library* files (typically `<PYTHON_X64_PATH>/libs`)  
+
+* **Delphi:**
+    - `DELPHI_PATH`: The *Borland Delphi* installation directory (for Windows only)  
+
+* **Makefile:**
+    - `CPU_TYPE`: Optimize binaries for the specified CPU type (defaults to "native"), see [`-march`](https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#x86-Options) for details!
+    - `CPLUSPLUS`:  If set to `1`, build CLI front-end from *C++* sources, otherwise from *plain C* sources (defaults to `0`)
+    - `NO_JAVA`: If set to `1`, the *Java* bindings are **not** built (defaults to `0`, i.e. *do* build)
+    - `NO_PYTHON`: If set to `1`, the *Python* bindings are **not** built (defaults to `0`, i.e. *do* build)  
+
+* **Windows:**
+    - `MSVC_PATH`: *Microsoft Visual C++* installation directory
+    - `PDOC_PATH`: *Pandoc v2.x* installation directory
+    - `GIT2_PATH`: *Git for Windows* (formerly *MSYS Git*) installation directory  
+
 
 # License
 
-**Copyright(c) 2016 LoRd_MuldeR &lt;mulder2@gmx.de&gt;, released under the MIT License.**  
+**Copyright(c) 2016-2017 LoRd_MuldeR &lt;mulder2@gmx.de&gt;, released under the MIT License.**  
 **Check <http://muldersoft.com/> or <http://muldersoft.sourceforge.net/> for updates!**
 
        Permission is hereby granted, free of charge, to any person obtaining a copy of this software
@@ -301,6 +563,31 @@ MHash-384 library should compile on any standard-compliant C/C++ compiler. In pa
 
 <https://opensource.org/licenses/MIT>
 
+
+# Version History
+
+## Version 1.1.0 [2017-07-??]
+
+* Re-generated the XOR- and MIX-tables with higher hamming distance for increased hash quality
+
+*  ***Note:*** This change, unfortunately, breaks compatibility with v1.0 hashes!
+
+* All language bindings have been *replaced* by full ports of the library to the respective language
+
+## Version 1.0.1 [2016-03-31]
+
+* Added language bindings for *Java*.
+
+* Added language bindings for *Microsoft.NET*.
+
+* Added language bindings for *Python*.
+
+* Added language bindings for *Delphi*.
+
+## Version 1.0.0 [2016-03-03]
+
+* First public release.
+
 &nbsp;
 
 [■](https://www.youtube.com/watch?v=dng06ZqI4Ss)