Commits

Craig Phillips committed 8d12e46

First commit

  • Participants

Comments (0)

Files changed (24)

File .hgignore

Empty file added.
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HashIt2", "HashIt\HashIt.csproj", "{D489B219-966C-4172-88FD-F99411BAF3B5}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D489B219-966C-4172-88FD-F99411BAF3B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D489B219-966C-4172-88FD-F99411BAF3B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D489B219-966C-4172-88FD-F99411BAF3B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D489B219-966C-4172-88FD-F99411BAF3B5}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

File HashIt/HashAlgorithmUC.Designer.cs

+namespace HashIt
+{
+    partial class HashAlgorithmUC
+    {
+        /// <summary> 
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary> 
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component Designer generated code
+
+        /// <summary> 
+        /// Required method for Designer support - do not modify 
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.chkHashSelected = new System.Windows.Forms.CheckBox();
+            this.txtHashValue = new System.Windows.Forms.TextBox();
+            this.txtHashName = new System.Windows.Forms.Label();
+            this.progHashProgress = new System.Windows.Forms.ProgressBar();
+            this.SuspendLayout();
+            // 
+            // chkHashSelected
+            // 
+            this.chkHashSelected.AutoSize = true;
+            this.chkHashSelected.Checked = true;
+            this.chkHashSelected.CheckState = System.Windows.Forms.CheckState.Checked;
+            this.chkHashSelected.Location = new System.Drawing.Point(144, 6);
+            this.chkHashSelected.Name = "chkHashSelected";
+            this.chkHashSelected.Size = new System.Drawing.Size(15, 14);
+            this.chkHashSelected.TabIndex = 31;
+            this.chkHashSelected.UseVisualStyleBackColor = true;
+            this.chkHashSelected.CheckedChanged += new System.EventHandler(this.chkHashSelected_CheckedChanged);
+            // 
+            // txtHashValue
+            // 
+            this.txtHashValue.Location = new System.Drawing.Point(165, 3);
+            this.txtHashValue.Name = "txtHashValue";
+            this.txtHashValue.ReadOnly = true;
+            this.txtHashValue.Size = new System.Drawing.Size(415, 20);
+            this.txtHashValue.TabIndex = 30;
+            // 
+            // txtHashName
+            // 
+            this.txtHashName.Location = new System.Drawing.Point(3, 6);
+            this.txtHashName.Name = "txtHashName";
+            this.txtHashName.Size = new System.Drawing.Size(135, 17);
+            this.txtHashName.TabIndex = 29;
+            this.txtHashName.Text = "Sample Hash:";
+            this.txtHashName.TextAlign = System.Drawing.ContentAlignment.TopRight;
+            // 
+            // progHashProgress
+            // 
+            this.progHashProgress.Location = new System.Drawing.Point(165, 3);
+            this.progHashProgress.Name = "progHashProgress";
+            this.progHashProgress.Size = new System.Drawing.Size(415, 20);
+            this.progHashProgress.Step = 1;
+            this.progHashProgress.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
+            this.progHashProgress.TabIndex = 32;
+            this.progHashProgress.Visible = false;
+            // 
+            // HashAlgorithmUC
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.Controls.Add(this.chkHashSelected);
+            this.Controls.Add(this.txtHashName);
+            this.Controls.Add(this.progHashProgress);
+            this.Controls.Add(this.txtHashValue);
+            this.Name = "HashAlgorithmUC";
+            this.Size = new System.Drawing.Size(589, 33);
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.CheckBox chkHashSelected;
+        private System.Windows.Forms.TextBox txtHashValue;
+        private System.Windows.Forms.Label txtHashName;
+        private System.Windows.Forms.ProgressBar progHashProgress;
+
+    }
+}

File HashIt/HashAlgorithmUC.cs

+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace HashIt
+{
+    public partial class HashAlgorithmUC : UserControl, INotifyPropertyChanged
+    {
+        string hashName = "";
+        bool hashSelected = false;
+        string hashValue = "";
+        bool showProgressBar = false;
+        bool enableCheckbox = true;
+        int progress = 0;
+
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        public HashAlgorithmUC()
+        {
+            InitializeComponent();
+            HashName = "";
+            HashSelected = false;
+            HashValue = "";
+            ShowProgressBar = false;
+            Progress = 0;
+        }
+
+        public string HashName
+        {
+            get { return hashName; }
+            set
+            {
+                hashName = value;
+                txtHashName.Text = hashName;
+                if (hashName.Length>0 && hashName.Substring(hashName.Length - 1, 1) != ":")
+                {
+                    txtHashName.Text += ":";
+                }
+                OnPropertyChanged("HashName");
+            }
+        }
+
+        public bool HashSelected
+        {
+            get { return hashSelected; }
+            set
+            {
+                hashSelected = value;
+                chkHashSelected.Checked = hashSelected;
+                OnPropertyChanged("HashSelected");
+            }
+        }
+
+        public string HashValue
+        {
+            get { return hashValue; }
+            set
+            {
+                hashValue = value.ToUpper();
+                txtHashValue.Text = hashValue;
+                OnPropertyChanged("HashValue");
+            }
+        }
+
+        public bool ShowProgressBar
+        {
+            get { return showProgressBar; }
+            set
+            {
+                showProgressBar = value;
+                progHashProgress.Visible = showProgressBar;
+                OnPropertyChanged("ShowProgressBar");
+            }
+        }
+
+        public int Progress
+        {
+            get { return progress; }
+            set
+            {
+                progress = value;
+                if (progress < 0) { progress = 0; }
+                if (progress > 100) { progress = 100; }
+                progHashProgress.Value = progress;
+                OnPropertyChanged("Progress");
+            }
+        }
+
+        public bool EnableCheckbox
+        {
+            get { return enableCheckbox; }
+            set
+            {
+                enableCheckbox = value;
+                chkHashSelected.Enabled = enableCheckbox;
+            }
+        }
+        
+        protected virtual void OnPropertyChanged(string propertyName)
+        {
+            if (PropertyChanged != null)
+            {
+                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+            }
+        }
+
+        private void chkHashSelected_CheckedChanged(object sender, EventArgs e)
+        {
+            HashSelected = chkHashSelected.Checked;
+        }
+    }
+}

File HashIt/HashAlgorithmUC.resx

+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

File HashIt/HashAlgorithms/ADLER32.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security.Cryptography;
+
+namespace HashIt
+{
+    public class Adler32 : HashAlgorithm
+    {
+        private ushort o_sum_1;
+        private ushort o_sum_2;
+
+        public Adler32()
+        {
+            Initialize();
+        }
+
+        public override int HashSize
+        {
+            get { return 32; }
+        }
+
+        public override void Initialize()
+        {
+            // reset the sum values
+            o_sum_1 = 1;
+            o_sum_2 = 0;
+        }
+
+        protected override void HashCore(byte[] p_array, int p_start_index, int p_count)
+        {
+            // process each byte in the array
+            for (int i = p_start_index; i < p_count; i++)
+            {
+                o_sum_1 = (ushort)((o_sum_1 + p_array[i]) % 65521);
+                o_sum_2 = (ushort)((o_sum_1 + o_sum_2)    % 65521);
+            }
+        }
+
+        protected override byte[] HashFinal()
+        {
+            // concat the two 16 bit values to form
+            // one 32-bit value
+            uint x_concat_value = (uint)((o_sum_2 << 16) | o_sum_1);
+            // use the bitconverter class to render the
+            // 32-bit integer into an array of bytes
+            return BitConverter.GetBytes(x_concat_value);
+        }
+    }
+}
+
+
+//The Adler32 checksum is a 32-bit checksum invented by Mark Adler for use in
+//the Zlib compression/decompression library. It is described in RFC 1950:
+//"ZLIB Compressed Data Format Specification version 3.3", including sample C code.
+
+//Such a checksum is included in every zlib stream
+//(note that zlib's format is different from that of gzip, though zlib also supports
+//gzip), and is checked by the decompressor to guard against accidental modification
+//or corruption. For protection against malicious modification, the use of a cryptographic
+//message authentication code is required, but these are generally much more expensive
+//(in terms of CPU time) than the Adler32 checksum.
+
+//Adler32 is also included as part of the Java standard library.
+//It is trivial to program, and doubtless there are dozens of implementations
+//in existence today; I have seen ones in C, C++, C#, Java, Ada95, and Perl.
+
+//Adler32 is significantly faster than any CRC algorithm I have seen,
+//and can easily hash well over 750 megabytes of data per second on a reasonably
+//modern machine.
+
+//The algorithm goes as follows:
+
+//S1, S2: unsigned 16-bit variables
+//S1 = 1
+//S2 = 0
+
+//foreach byte b in input
+//    S1 = (S1 + b) % 65521
+//    S2 = (S2 + S1) % 65521
+
+//The final checksum is S2 || S1
+
+//65521 is the largest prime smaller than 2**16. You can optimize an implementation
+//significantly by realizing that, if S1 and S2 are stored in 32-bit registers,
+//then you hash quite a bit of data without causing the values to overflow; thus,
+//you only have to do the modulo operation for every 4 kilobytes or so of input;
+//see RFC 1950 for details.
+
+//There is one important caveat about using Adler32. Unlike CRCs, it is not the
+//case that all the bits of the checksum rely on all the bits of the input; thus,
+//hashing strings of a short length, or with little entropy, will result in
+//checksums with unevenly distributed bits. In particular, the higher bits will
+//often be zero when hashing short strings. 
+

File HashIt/HashAlgorithms/BuiltInHashes.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security.Cryptography;
+
+namespace HashIt
+{
+    // This file exists to create "dummy" classes that simply inherit from the internal Hash algorithms.
+    // This allows the routine in the MainForm that iterates through all of the classes that derive from HashAlgorithm
+    // within the current (executing assembly) to pick up the required "internal" Hash algorithm implementations.
+    public class SHA1 : SHA1Managed
+    {
+    }
+
+    public class SHA256 : SHA256Managed
+    {
+    }
+
+    public class SHA512 : SHA512Managed
+    {
+    }
+
+    public class RIPEMD160 : RIPEMD160Managed
+    {
+    }
+
+}

File HashIt/HashAlgorithms/CRC32.cs

+using System;
+using System.Security.Cryptography;
+
+namespace HashIt
+{
+	public class CRC32 : HashAlgorithm
+	{
+		public const UInt32 DefaultPolynomial = 0xedb88320;
+		public const UInt32 DefaultSeed = 0xffffffff;
+
+		private UInt32 hash;
+		private UInt32 seed;
+		private UInt32[] table;
+		private static UInt32[] defaultTable;
+
+		public CRC32()
+		{
+			table = InitializeTable(DefaultPolynomial);
+			seed = DefaultSeed;
+			Initialize();
+		}
+
+		public CRC32(UInt32 polynomial, UInt32 seed)
+		{
+			table = InitializeTable(polynomial);
+			this.seed = seed;
+			Initialize();
+		}
+
+		public override void Initialize()
+		{
+			hash = seed;
+		}
+
+		protected override void HashCore(byte[] buffer, int start, int length)
+		{
+			hash = CalculateHash(table, hash, buffer, start, length);
+		}
+
+		protected override byte[] HashFinal()
+		{
+			byte[] hashBuffer = UInt32ToBigEndianBytes(~hash);
+			this.HashValue = hashBuffer;
+			return hashBuffer;
+		}
+
+		public override int HashSize
+		{
+			get { return 32; }
+		}
+
+		public static UInt32 Compute(byte[] buffer)
+		{
+			return ~CalculateHash(InitializeTable(DefaultPolynomial), DefaultSeed, buffer, 0, buffer.Length);
+		}
+
+		public static UInt32 Compute(UInt32 seed, byte[] buffer)
+		{
+			return ~CalculateHash(InitializeTable(DefaultPolynomial), seed, buffer, 0, buffer.Length);
+		}
+
+		public static UInt32 Compute(UInt32 polynomial, UInt32 seed, byte[] buffer)
+		{
+			return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length);
+		}
+
+		private static UInt32[] InitializeTable(UInt32 polynomial)
+		{
+			if (polynomial == DefaultPolynomial && defaultTable != null)
+				return defaultTable;
+
+			UInt32[] createTable = new UInt32[256];
+			for (int i = 0; i < 256; i++)
+			{
+				UInt32 entry = (UInt32)i;
+				for (int j = 0; j < 8; j++)
+					if ((entry & 1) == 1)
+						entry = (entry >> 1) ^ polynomial;
+					else
+						entry = entry >> 1;
+				createTable[i] = entry;
+			}
+
+			if (polynomial == DefaultPolynomial)
+				defaultTable = createTable;
+
+			return createTable;
+		}
+
+		private static UInt32 CalculateHash(UInt32[] table, UInt32 seed, byte[] buffer, int start, int size)
+		{
+			UInt32 crc = seed;
+			for (int i = start; i < size; i++)
+				unchecked
+				{
+					crc = (crc >> 8) ^ table[buffer[i] ^ crc & 0xff];
+				}
+			return crc;
+		}
+
+		private byte[] UInt32ToBigEndianBytes(UInt32 x)
+		{
+			return new byte[] {
+			(byte)((x >> 24) & 0xff),
+			(byte)((x >> 16) & 0xff),
+			(byte)((x >> 8) & 0xff),
+			(byte)(x & 0xff)
+			};
+		}
+	}
+}

File HashIt/HashAlgorithms/MD5Managed.cs

+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Security.Cryptography;
+
+namespace HashIt
+{
+    /// <summary>
+    /// MD5Managed: A HashAlgorithm implementation that acts as a thin wrapper
+    /// around a C# translation of the MD5 reference implementation. The C code
+    /// has been translated as closely as possible so that most of the original
+    /// structure remains and comparisons between the two are straightforward.
+    /// </summary>
+    /// <remarks>
+    /// Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
+    /// 
+    /// Specification:
+    /// RFC1321 - The MD5 Message-Digest Algorithm
+    /// http://www.faqs.org/rfcs/rfc1321.html
+    /// 
+    /// Original license:
+    /// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+    /// rights reserved.
+    /// 
+    /// License to copy and use this software is granted provided that it
+    /// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+    /// Algorithm" in all material mentioning or referencing this software
+    /// or this function.
+    /// 
+    /// License is also granted to make and use derivative works provided
+    /// that such works are identified as "derived from the RSA Data
+    /// Security, Inc. MD5 Message-Digest Algorithm" in all material
+    /// mentioning or referencing the derived work.
+    /// 
+    /// RSA Data Security, Inc. makes no representations concerning either
+    /// the merchantability of this software or the suitability of this
+    /// software for any particular purpose. It is provided "as is"
+    /// without express or implied warranty of any kind.
+    /// 
+    /// These notices must be retained in any copies of any part of this
+    /// documentation and/or software.
+    /// </remarks>
+    class MD5 : HashAlgorithm
+    {
+        // Current context
+        private readonly MD5_CTX _context = new MD5_CTX();
+        // Last hash result
+        private readonly byte[] _digest = new byte[16];
+
+        /// <summary>
+        /// Initializes a new instance.
+        /// </summary>
+        public MD5()
+        {
+            MD5Init(_context);
+        }
+
+        /// <summary>
+        /// Initializes internal state.
+        /// </summary>
+        public override void Initialize()
+        {
+            MD5Init(_context);
+        }
+
+        /// <summary>
+        /// Updates the hash code with the data provided.
+        /// </summary>
+        /// <param name="array">Data to hash.</param>
+        /// <param name="ibStart">Start position.</param>
+        /// <param name="cbSize">Number of bytes.</param>
+        protected override void HashCore(byte[] array, int ibStart, int cbSize)
+        {
+            MD5Update(_context, array, (uint)ibStart, (uint)cbSize);
+        }
+
+        /// <summary>
+        /// Finalizes the hash code and returns it.
+        /// </summary>
+        /// <returns></returns>
+        protected override byte[] HashFinal()
+        {
+            MD5Final(_digest, _context);
+            return Hash;
+        }
+
+        /// <summary>
+        /// Returns the hash as an array of bytes.
+        /// </summary>
+        public override byte[] Hash
+        {
+            get
+            {
+                return _digest;
+            }
+        }
+
+        // Return size of hash in bits.
+        public override int HashSize
+        {
+            get
+            {
+                return _digest.Length * 8;
+            }
+        }
+
+        ///////////////////////////////////////////////
+        // MD5 reference implementation begins here. //
+        ///////////////////////////////////////////////
+
+        /* MD5 context. */
+        private class MD5_CTX
+        {
+            public readonly uint[] state;   /* state (ABCD) */
+            public readonly uint[] count;   /* number of bits, modulo 2^64 (lsb first) */
+            public readonly byte[] buffer;  /* input buffer */
+
+            public MD5_CTX()
+            {
+                state = new uint[4];
+                count = new uint[2];
+                buffer = new byte[64];
+            }
+
+            public void Clear()
+            {
+                Array.Clear(state, 0, state.Length);
+                Array.Clear(count, 0, count.Length);
+                Array.Clear(buffer, 0, buffer.Length);
+            }
+        }
+
+        /* Constants for MD5Transform routine. */
+        private const int S11 = 7;
+        private const int S12 = 12;
+        private const int S13 = 17;
+        private const int S14 = 22;
+        private const int S21 = 5;
+        private const int S22 = 9;
+        private const int S23 = 14;
+        private const int S24 = 20;
+        private const int S31 = 4;
+        private const int S32 = 11;
+        private const int S33 = 16;
+        private const int S34 = 23;
+        private const int S41 = 6;
+        private const int S42 = 10;
+        private const int S43 = 15;
+        private const int S44 = 21;
+
+        private static byte[] PADDING;
+
+        [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification = "More compact this way")]
+        static MD5()
+        {
+            PADDING = new byte[64];
+            PADDING[0] = 0x80;
+        }
+
+        /* F, G, H and I are basic MD5 functions. */
+        private static uint F(uint x, uint y, uint z) { return (((x) & (y)) | ((~x) & (z))); }
+        private static uint G(uint x, uint y, uint z) { return (((x) & (z)) | ((y) & (~z))); }
+        private static uint H(uint x, uint y, uint z) { return ((x) ^ (y) ^ (z)); }
+        private static uint I(uint x, uint y, uint z) { return ((y) ^ ((x) | (~z))); }
+
+        /* ROTATE_LEFT rotates x left n bits. */
+        private static uint ROTATE_LEFT(uint x, int n) { return (((x) << (n)) | ((x) >> (32 - (n)))); }
+
+        /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+           Rotation is separate from addition to prevent recomputation. */
+        private static void FF(ref uint a, uint b, uint c, uint d, uint x, int s, uint ac)
+        {
+            (a) += F((b), (c), (d)) + (x) + (uint)(ac);
+            (a) = ROTATE_LEFT((a), (s));
+            (a) += (b);
+        }
+        private static void GG(ref uint a, uint b, uint c, uint d, uint x, int s, uint ac)
+        {
+            (a) += G((b), (c), (d)) + (x) + (uint)(ac);
+            (a) = ROTATE_LEFT((a), (s));
+            (a) += (b);
+        }
+        private static void HH(ref uint a, uint b, uint c, uint d, uint x, int s, uint ac)
+        {
+            (a) += H((b), (c), (d)) + (x) + (uint)(ac);
+            (a) = ROTATE_LEFT((a), (s));
+            (a) += (b);
+        }
+        private static void II(ref uint a, uint b, uint c, uint d, uint x, int s, uint ac)
+        {
+            (a) += I((b), (c), (d)) + (x) + (uint)(ac);
+            (a) = ROTATE_LEFT((a), (s));
+            (a) += (b);
+        }
+
+        /* MD5 initialization. Begins an MD5 operation, writing a new context. */
+        private static void MD5Init(MD5_CTX context)  /* context */
+        {
+            context.count[0] = context.count[1] = 0;
+
+            /* Load magic initialization constants. */
+            context.state[0] = 0x67452301;
+            context.state[1] = 0xefcdab89;
+            context.state[2] = 0x98badcfe;
+            context.state[3] = 0x10325476;
+        }
+
+        /* MD5 block update operation. Continues an MD5 message-digest
+           operation, processing another message block, and updating the
+           context. */
+        private static void MD5Update(MD5_CTX context,  /* context */
+                                      byte[] input,     /* input block */
+                                      uint inputIndex,  // Starting index for input block
+                                      uint inputLen)    /* length of input block */
+        {
+            /* Compute number of bytes mod 64 */
+            uint index = (uint)((context.count[0] >> 3) & 0x3F);
+
+            /* Update number of bits */
+            if ((context.count[0] += ((uint)inputLen << 3)) < ((uint)inputLen << 3))
+            {
+                context.count[1]++;
+            }
+            context.count[1] += ((uint)inputLen >> 29);
+
+            uint partLen = 64 - index;
+
+            /* Transform as many times as possible. */
+            uint i = 0;
+            if (inputLen >= partLen)
+            {
+                Buffer.BlockCopy(input, (int)inputIndex, context.buffer, (int)index, (int)partLen);
+                MD5Transform(context.state, context.buffer, 0);
+
+                for (i = partLen; i + 63 < inputLen; i += 64)
+                {
+                    MD5Transform(context.state, input, i);
+                }
+
+                index = 0;
+            }
+
+            /* Buffer remaining input */
+            Buffer.BlockCopy(input, (int)(inputIndex + i), context.buffer, (int)index, (int)(inputLen - i));
+        }
+
+        /* MD5 finalization. Ends an MD5 message-digest operation, writing the
+           the message digest and zeroizing the context. */
+        private static void MD5Final(byte[] digest,    /* message digest */
+                                     MD5_CTX context)  /* context */
+        {
+            byte[] bits = new byte[8];
+
+            /* Save number of bits */
+            Encode(bits, context.count, 8);
+
+            /* Pad out to 56 mod 64. */
+            uint index = (uint)((context.count[0] >> 3) & 0x3f);
+            uint padLen = (index < 56) ? (56 - index) : (120 - index);
+            MD5Update(context, PADDING, 0, padLen);
+
+            /* Append length (before padding) */
+            MD5Update(context, bits, 0, 8);
+
+            /* Store state in digest */
+            Encode(digest, context.state, 16);
+
+            /* Zeroize sensitive information. */
+            context.Clear();
+        }
+
+        /* MD5 basic transformation. Transforms state based on block. */
+        private static void MD5Transform(uint[] state,
+                                         byte[] block,
+                                         uint blockIndex)
+        {
+            uint a = state[0], b = state[1], c = state[2], d = state[3];
+            uint[] x = new uint[16];
+
+            Decode(x, block, blockIndex, 64);
+
+            /* Round 1 */
+            FF(ref a, b, c, d, x[0],  S11, 0xd76aa478); /* 1 */
+            FF(ref d, a, b, c, x[1],  S12, 0xe8c7b756); /* 2 */
+            FF(ref c, d, a, b, x[2],  S13, 0x242070db); /* 3 */
+            FF(ref b, c, d, a, x[3],  S14, 0xc1bdceee); /* 4 */
+            FF(ref a, b, c, d, x[4],  S11, 0xf57c0faf); /* 5 */
+            FF(ref d, a, b, c, x[5],  S12, 0x4787c62a); /* 6 */
+            FF(ref c, d, a, b, x[6],  S13, 0xa8304613); /* 7 */
+            FF(ref b, c, d, a, x[7],  S14, 0xfd469501); /* 8 */
+            FF(ref a, b, c, d, x[8],  S11, 0x698098d8); /* 9 */
+            FF(ref d, a, b, c, x[9],  S12, 0x8b44f7af); /* 10 */
+            FF(ref c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+            FF(ref b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+            FF(ref a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+            FF(ref d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+            FF(ref c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+            FF(ref b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+            /* Round 2 */
+            GG(ref a, b, c, d, x[1],  S21, 0xf61e2562); /* 17 */
+            GG(ref d, a, b, c, x[6],  S22, 0xc040b340); /* 18 */
+            GG(ref c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+            GG(ref b, c, d, a, x[0],  S24, 0xe9b6c7aa); /* 20 */
+            GG(ref a, b, c, d, x[5],  S21, 0xd62f105d); /* 21 */
+            GG(ref d, a, b, c, x[10], S22, 0x02441453); /* 22 */
+            GG(ref c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+            GG(ref b, c, d, a, x[4],  S24, 0xe7d3fbc8); /* 24 */
+            GG(ref a, b, c, d, x[9],  S21, 0x21e1cde6); /* 25 */
+            GG(ref d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+            GG(ref c, d, a, b, x[3],  S23, 0xf4d50d87); /* 27 */
+            GG(ref b, c, d, a, x[8],  S24, 0x455a14ed); /* 28 */
+            GG(ref a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+            GG(ref d, a, b, c, x[2],  S22, 0xfcefa3f8); /* 30 */
+            GG(ref c, d, a, b, x[7],  S23, 0x676f02d9); /* 31 */
+            GG(ref b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+            /* Round 3 */
+            HH(ref a, b, c, d, x[5],  S31, 0xfffa3942); /* 33 */
+            HH(ref d, a, b, c, x[8],  S32, 0x8771f681); /* 34 */
+            HH(ref c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+            HH(ref b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+            HH(ref a, b, c, d, x[1],  S31, 0xa4beea44); /* 37 */
+            HH(ref d, a, b, c, x[4],  S32, 0x4bdecfa9); /* 38 */
+            HH(ref c, d, a, b, x[7],  S33, 0xf6bb4b60); /* 39 */
+            HH(ref b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+            HH(ref a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+            HH(ref d, a, b, c, x[0],  S32, 0xeaa127fa); /* 42 */
+            HH(ref c, d, a, b, x[3],  S33, 0xd4ef3085); /* 43 */
+            HH(ref b, c, d, a, x[6],  S34, 0x04881d05); /* 44 */
+            HH(ref a, b, c, d, x[9],  S31, 0xd9d4d039); /* 45 */
+            HH(ref d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+            HH(ref c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+            HH(ref b, c, d, a, x[2],  S34, 0xc4ac5665); /* 48 */
+
+            /* Round 4 */
+            II(ref a, b, c, d, x[0],  S41, 0xf4292244); /* 49 */
+            II(ref d, a, b, c, x[7],  S42, 0x432aff97); /* 50 */
+            II(ref c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+            II(ref b, c, d, a, x[5],  S44, 0xfc93a039); /* 52 */
+            II(ref a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+            II(ref d, a, b, c, x[3],  S42, 0x8f0ccc92); /* 54 */
+            II(ref c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+            II(ref b, c, d, a, x[1],  S44, 0x85845dd1); /* 56 */
+            II(ref a, b, c, d, x[8],  S41, 0x6fa87e4f); /* 57 */
+            II(ref d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+            II(ref c, d, a, b, x[6],  S43, 0xa3014314); /* 59 */
+            II(ref b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+            II(ref a, b, c, d, x[4],  S41, 0xf7537e82); /* 61 */
+            II(ref d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+            II(ref c, d, a, b, x[2],  S43, 0x2ad7d2bb); /* 63 */
+            II(ref b, c, d, a, x[9],  S44, 0xeb86d391); /* 64 */
+
+            state[0] += a;
+            state[1] += b;
+            state[2] += c;
+            state[3] += d;
+
+            /* Zeroize sensitive information. */
+            Array.Clear(x, 0, x.Length);
+        }
+
+        /* Encodes input (UINT4) into output (unsigned char). Assumes len is
+           a multiple of 4. */
+        private static void Encode(byte[] output,
+                                   uint[] input,
+                                   uint len)
+        {
+            for (uint i = 0, j = 0; j < len; i++, j += 4)
+            {
+                output[j] = (byte)(input[i] & 0xff);
+                output[j + 1] = (byte)((input[i] >> 8) & 0xff);
+                output[j + 2] = (byte)((input[i] >> 16) & 0xff);
+                output[j + 3] = (byte)((input[i] >> 24) & 0xff);
+            }
+        }
+
+        /* Decodes input (unsigned char) into output (UINT4). Assumes len is
+           a multiple of 4. */
+        private static void Decode(uint[] output,
+                                   byte[] input,
+                                   uint inputIndex,
+                                   uint len)
+        {
+            for (uint i = 0, j = 0; j < len; i++, j += 4)
+            {
+                output[i] = ((uint)input[inputIndex + j]) |
+                    (((uint)input[inputIndex + j + 1]) << 8) |
+                    (((uint)input[inputIndex + j + 2]) << 16) |
+                    (((uint)input[inputIndex + j + 3]) << 24);
+            }
+        }
+    }
+}

File HashIt/HashAlgorithms/Skein.cs

+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security.Cryptography;
+
+namespace HashIt.HashAlgorithms
+{
+    public class Skein512 : HashAlgorithm
+    {
+        private byte[] _blockBuffer;
+        private UInt64[] _blockWords;
+        private byte[] _config;
+        private UInt32 _outputSize;
+        private UInt32 _blockSize;
+        private bool _initialized;
+
+        private UBI _ubi;
+
+        public override int HashSize
+        {
+            get { return (int)_outputSize; }
+        }
+        public override int InputBlockSize
+        {
+            get { return (int)_blockSize; }
+        }
+        public override int OutputBlockSize
+        {
+            get { return (int)_outputSize; }
+        }
+
+        public Skein512() : base()
+        {
+            UInt32 blockSizeInBits = 512;
+            UInt32 outputSizeInBits = 256;
+            this._outputSize = outputSizeInBits / 8;
+            this._blockSize = blockSizeInBits / 8;
+
+        }
+
+        public override void Initialize()
+        {
+            //
+            // TODO: Initial UBI can be statically specified as per Appendix B
+            //
+
+
+            _initialized = true;
+            //
+            // Initialize some book keeping
+            //
+            _ubi = new UBI((UInt32)this.InputBlockSize);
+            _blockBuffer = new byte[this.InputBlockSize];
+
+            // Do first UBI with config
+            // Per spec this is
+            // K' := 0^Nb
+            // G0 := UBI( K', C, Tcfg 2^120)
+            //
+            // Copy config into buffer (also zero-pads the rest of the buffer)
+            //
+            _config = EncodeConfig();
+            Array.Copy(_config, _blockBuffer, _config.Length);
+            _blockWords = Util.ConvertLSBFirstToUInt64(_blockBuffer);
+
+            //
+            // In Skein 1.0, there was a mistake in the reference impl. (and the test vectors)
+            // where block size was used here instead of config size. This was fixed in 1.1's test vectors
+            //
+            Tweak tweak = Tweak.EncodeTweak((UInt64)_config.Length, false, TweakType.Configuration, true, true);
+            _ubi.Update(_blockWords, tweak);
+
+
+        }
+
+
+
+        protected override void HashCore(byte[] data, int indexStart, int size)
+        {
+            if (!_initialized)
+            {
+                Initialize();
+            }
+            int positionInInput = 0; // Index into input array
+            int nextBlockSize = 0;
+
+
+            while (positionInInput < indexStart + size)
+            {
+                nextBlockSize = Math.Min(InputBlockSize, (indexStart + size) - positionInInput);
+
+
+                //
+                // Common case - we have a block that 'fits' our buffer
+                //
+                Array.Copy(data, positionInInput, _blockBuffer, 0, nextBlockSize);
+                if (nextBlockSize != InputBlockSize)
+                {
+                    //
+                    // Pad out remaining part of block buffer
+                    //
+                    Array.Clear(_blockBuffer, nextBlockSize, InputBlockSize - nextBlockSize);
+                }
+
+                Util.ConvertLSBFirstToUInt64(_blockBuffer, ref _blockWords);
+                //
+                // Construct tweak value
+                // Position = current position/bytes processed
+                // First - whether the current no. of bytes processed is <= a full block
+                // Final = whether we've finished all data
+                //
+                positionInInput += nextBlockSize; //update before tweak
+                Tweak tweak = Tweak.EncodeTweak((UInt64)(positionInInput - indexStart), false, TweakType.Message,
+                                                    positionInInput - indexStart <= InputBlockSize,
+                                                    ((indexStart + size) - positionInInput) == 0);
+
+                _ubi.Update(_blockWords, tweak);
+            }
+
+        }
+
+        protected override byte[] HashFinal()
+        {
+            UInt64[] output = new UInt64[this.InputBlockSize / sizeof(UInt64)];
+
+            //
+            // Output function 
+            //
+            // Output ( G, No) := UBI ( G, ToBytes(0,8), Tout 2^120) ||
+            //                    UBI ( G, ToBytes(1,8), Tout 2^120) ||...
+            //
+            Tweak tweak;
+            UInt32 outputBlocks = (_outputSize - 1) / (UInt32)InputBlockSize + 1;
+            for (int i = 0; i < outputBlocks; i++)
+            {
+                output[0] = (UInt64)i;
+                tweak = Tweak.EncodeTweak(sizeof(UInt64), false, TweakType.Output, i == 0, i == outputBlocks - 1);
+                _ubi.Update(output, tweak);
+            }
+            if (_ubi.CurrentOutputState.Length * sizeof(UInt64) > _outputSize)
+            {
+                //
+                // We don't want to return more bytes than asked for
+                //
+                UInt64[] outputSmallHash = new UInt64[_outputSize / sizeof(UInt64)];
+                Array.Copy(_ubi.CurrentOutputState, outputSmallHash, outputSmallHash.Length);
+                return Util.ConvertUInt64ToLSBFirst(outputSmallHash);
+            }
+            else
+            {
+                return Util.ConvertUInt64ToLSBFirst(_ubi.CurrentOutputState);
+            }
+        }
+
+
+
+        internal byte[] EncodeConfig()
+        {
+
+            //
+            // Returns a 32 byte array with configuration encoded as per spec.
+            //
+            // 0-4 Schema Identifier ('SHA3')
+            // 4-6 Version Number (1)
+            // 6-8 reserved (0)
+            // 8-16 output length in bits (and not bytes)
+            // 16-17 tree-leaf size
+            // 17-18 tree leaf fan out
+            // 18-19 max tree height
+            // 19-32 reserved (0)
+            // N.B we don't support tree mode so we don't take as many params as we should/
+            //
+
+            //
+            // TODO: Have static versions for the known output sizes and intiail UBI per appendix b
+            // TODO: Fix getbytes call with bit shift if it is faster than BitConverter 
+            //(doubtful since BitConverter seems to do a direct assignment using unsafe code)
+            // TODO: Make it work regardless of machine endianness (this doesn't work on non LSB machines now)
+            //
+            byte[] l = BitConverter.GetBytes((UInt64)this.OutputBlockSize * 8);
+            return new byte[32] { 
+            (byte)'S', (byte)'H', (byte)'A', (byte)'3', // SHA3 string
+            1,0,  // Version number (LSB)
+            0,0, // reserved
+            l[0], l[1], l[2], l[3], l[4],l[5],l[6],l[7], // 8 bytes of length
+            0,0,0,  // No support for tree mode
+            0,0,0,0,0,0,0,0,0,0,0,0,0 // Reserved
+            };
+        }
+    }
+
+    //
+    // Various Type values for tweaks as per spec.
+    public enum TweakType
+    {
+        Key = 0,
+        Configuration = 4,
+        Personalization = 8,
+        PublicKey = 12,
+        KeyIdentifier = 16,
+        Nonce = 20,
+        Message = 48,
+        Output = 63
+    };
+
+    public struct Tweak
+    {
+        //
+        // Simple wrapper around a 128-bit integer
+        //
+
+        public UInt64 low64 { get; set; }
+        public UInt64 high64 { get; set; }
+
+        private Tweak(UInt64 low, UInt64 high)
+            : this()
+        {
+
+            low64 = low;
+            high64 = high;
+        }
+
+        internal static Tweak EncodeTweak(UInt64 position, bool bitPad, TweakType type, bool first, bool final)
+        {
+
+            //
+            // Takes tweak parameters and encodes them in a 128 bit value. The lower half of the 128 byte value (only the position)
+            // is stuck in low64 and the high half in stuck in high64.
+            //
+            // N.B SimpleSkeinManaged specifies that position can be upto 2^96 but we support only 2^64. We could add support by rolling our own BigInteger
+            //
+            // The encoding is as follows (ASCII art not to scale)
+            //
+            // 128             120                   112            96                                    0
+            // --------------------------------------------------------------------------------------------
+            // F1|F2|    Type   |B|       TreeLevel   |   reserved  |      Position                       |
+            //   |  |           | |                   |             |                                     |
+            // --------------------------------------------------------------------------------------------
+            //  F1 = First
+            //  F2 = Final
+            //  B  - BitPad
+            //
+
+            Tweak tweak = new Tweak(0, 0);
+            tweak.high64 = 0;
+
+            //
+            // The shift numbers are calculated using 64 - (128 - end-byte-from-diagram-above)
+            //
+            if (final) tweak.high64 |= (UInt64)1L << 63; // Set F1 in diagram above
+            if (first) tweak.high64 |= (UInt64)1L << 62; // Set F2 in diagram above
+            tweak.high64 |= (UInt64)type << 56; // Set type
+            if (bitPad) tweak.high64 |= (UInt64)1L << 55; // Set bit pad
+
+            tweak.low64 = position;
+            return tweak;
+        }
+    }
+
+    public class Util
+    {
+        public static UInt64[] ConvertLSBFirstToUInt64(byte[] input)
+        {
+
+            UInt64[] output = new UInt64[input.Length / sizeof(UInt64)];
+            ConvertLSBFirstToUInt64(input, ref output);
+            return output;
+        }
+
+        public static void ConvertLSBFirstToUInt64(byte[] input, ref UInt64[] output)
+        {
+
+            //
+            // Takes an array of LSB-first bytes and converts them into UInt64
+            //
+
+
+            if (input.Length / sizeof(UInt64) != output.Length)
+            {
+                throw new ArgumentException("Output UInt64 array not of right size.");
+            }
+
+            int sizeUInt64 = sizeof(UInt64);
+            //Debug.Assert(input.Length % sizeUInt64 == 0);
+            if (input.Length % sizeUInt64 != 0)
+            {
+                throw new ArgumentException("Input LSB array not of right size. Did you forget to zero pad?");
+            }
+
+            for (int i = 0; i <= (input.Length - sizeUInt64); i += sizeUInt64)
+            {
+                //
+                // TODO: This doesn't work on BigEndian machines
+                //
+                //Debug.Assert(BitConverter.IsLittleEndian);
+                if (!BitConverter.IsLittleEndian)
+                {
+                    throw new NotImplementedException("Not implemented for big endian machines yet");
+                }
+                output[i / sizeUInt64] = BitConverter.ToUInt64(input, i);
+            }
+
+        }
+
+        public static byte[] ConvertUInt64ToLSBFirst(UInt64[] input)
+        {
+            //
+            // Takes an array of unsigned 64 bit integers and converts them into a 
+            // a byte array with LSB first
+            //
+
+            byte[] output = new byte[input.Length * sizeof(UInt64)];
+            for (int i = 0; i < input.Length; i++)
+            {
+                Array.Copy(BitConverter.GetBytes(input[i]), 0, output, i * sizeof(UInt64), sizeof(UInt64));
+            }
+            return output;
+        }
+
+        public static byte[] ZeroPad(byte[] input, int blockSizeInBytes)
+        {
+
+            //
+            // Takes a block size and pads it until it becomes a multiple of blockSizeInBytes
+            //
+
+            if (input.Length % blockSizeInBytes == 0)
+            {
+                //
+                // Already correct length - nothing for us to do
+                //
+                return input;
+            }
+
+            int finalBlocks = (input.Length - 1) / blockSizeInBytes + 1;
+
+            byte[] output = new byte[finalBlocks * blockSizeInBytes];
+
+            //
+            // .NET makes sure arrays are initialized to 0. All that's left is to
+            // copy old data over
+            //
+
+            Array.Copy(input, output, input.Length);
+            return output;
+
+        }
+
+
+        public static byte[] ByteArrayfromHex(String hexString)
+        {
+            //
+            // Takes an input string consisting of hex characters and returns a byte array
+            //
+            byte[] result = new byte[hexString.Length / 2];
+            for (int i = 0; i < result.Length; i++)
+            {
+                result[i] = (byte)Convert.ToInt32(hexString.Substring(i * 2, 2), 16);
+            }
+            return result;
+        }
+
+        public static string HexStringFromByteArray(byte[] data)
+        {
+            //
+            // Takes a byte array and returns a hex string as output
+            // 
+            string output = String.Empty;
+            foreach (byte b in data)
+            {
+                output += String.Format("{0:X2}", b);
+            }
+            return output;
+        }
+
+
+    }
+
+    internal class UBI
+    {
+        //
+        // Unique block iteration mode as per spec. Hard coded to use Threefish at the moment
+        //
+
+        // Intermediate value so far
+        private UInt64[] _Hi;
+        private Threefish.ThreeFishBlockSize _blockSize;
+
+        public UInt64[] CurrentOutputState { get { return _Hi; } }
+
+        internal UBI(UInt64[] g, UInt32 blockSizeInBytes)
+        {
+            _Hi = g;
+            _blockSize = (Threefish.ThreeFishBlockSize)(blockSizeInBytes);
+
+        }
+
+        internal UBI(UInt32 blockSizeInBytes) :
+            this(new UInt64[blockSizeInBytes / sizeof(UInt64)], blockSizeInBytes)
+        {
+            //
+            // Construct empty internal state
+            //           
+        }
+
+
+
+        internal void Update(UInt64[] message, Tweak tweak)
+        {
+            //
+            // Takes encoded tweak value and message, encrypts using current state as key and XORs
+            // result with message. The block size is determined by looking at input message length
+            // TODO: Reuse block cipher instance
+            //
+
+            if (_Hi.Length != message.Length)
+            {
+                throw new InvalidOperationException("Can't change block size in mid flight");
+
+            }
+            Threefish threeFish = new Threefish(_Hi, tweak, _blockSize);
+            threeFish.Encrypt(message, _Hi);
+
+            for (int i = 0; i < _Hi.Length; i++)
+            {
+
+                _Hi[i] ^= message[i];
+            }
+
+        }
+    }
+
+
+    public class Threefish
+    {
+        //
+        //TODO: Perf sucks right now. The reference impl. precomputes the key schedule and unrolls this loop
+        // It also avoids memory allocations as much as possible whereas we allocate arrays all over the place
+        //
+
+        public enum ThreeFishBlockSize
+        {
+            BLOCKSIZE_256_BITS = 32,
+            BLOCKSIZE_512_BITS = 64,
+            BLOCKSIZE_1024_BITS = 128
+        }
+
+        private enum ThreeFishRounds
+        {
+            ROUNDS_72 = 72,
+            ROUNDS_80 = 80
+        }
+
+        //
+        // Define word permutation Pi(i) for various Nw as per spec (Table 3)
+        //
+        private static byte[] PI_I_Nw_4 = new byte[4] { 0, 3, 2, 1 };
+        private static byte[] PI_I_Nw_8 = new byte[8] { 2, 1, 4, 7, 6, 5, 0, 3 };
+        private static byte[] PI_I_Nw_16 = new byte[16] { 0, 9, 2, 13, 6, 11, 4, 15, 10, 7, 12, 3, 14, 5, 8, 1 };
+
+        private byte[] PermutationPi { get; set; }
+        //
+        //Rotation constants Rd,j for each Nw as per spec (Table 4)
+        //
+
+        private static int[][] Rdj_Nw_4 = {
+                                      new int[]{5,56},
+                                      new int[]{36,28},
+                                      new int[]{13,46},
+                                      new int[]{58,44},
+                                      new int[]{26,20},
+                                      new int[]{53,35},
+                                      new int[]{11,42},
+                                      new int[]{59,50}
+                                    };
+
+        private static int[][] Rdj_Nw_8 = {
+
+                                             new int[]{38,30,50,53},
+                                             new int[]{48,20,43,31},
+                                             new int[]{34,14,15,27},
+                                             new int[]{26,12,58,7},
+                                             new int[]{33,49,8,42},
+                                             new int[]{39,27,41,14},
+                                             new int[]{29,26,11,9},
+                                             new int[]{33,51,39,35},
+                                         };
+
+        private static int[][] Rdj_Nw_16 = {
+
+                                              new int[]{55,43,37,40,16,22,38,12},
+                                              new int[]{25,25,46,13,14,13,52, 57},
+                                              new int[]{33,8,18,57,21,12,32,54},
+                                              new int[]{34, 43,25,60, 44,9,59,34},
+                                              new int[]{28,7,47,48,51,9,35,41},
+                                              new int[]{17,6,18,25,43,42,40,15},
+                                              new int[]{58, 7, 32,45,19,18,2,56},
+                                              new int[]{47,49,27,58,37,48,53,56}
+
+
+                                          };
+
+        private int[][] RotationConstants = null;
+
+
+        public ThreeFishBlockSize BlockSize { get; set; }
+
+        //
+        // Key as  UInt64 words
+        //
+
+        public UInt64[] KeyWords { get; set; }
+
+
+
+        //
+        // No. of rounds for the cipher. Function of block size
+        //
+        private ThreeFishRounds _rounds = 0;
+
+        //
+        // No. of words in key/plain text. Nw from the paper
+        //
+        private int _numWords = 0;
+
+        //
+        // Vd, Ed, fd and Ksd from paper
+        //
+
+        private UInt64[] _vd;
+        private UInt64[] _ed;
+        private UInt64[] _fd;
+        private UInt64[] _kdi;
+
+        //
+        // Ts from paper (t0, t1 and t2)
+        //
+
+        private UInt64[] _ts = { 0, 0, 0 };
+
+        //
+        // kNw from paper. Set to 2^64/3
+        //
+        private UInt64 _kNw = 0x5555555555555555L;
+
+
+        public Threefish(UInt64[] key, Tweak tweak, ThreeFishBlockSize blockSize)
+        {
+            //
+            // TODO: Move non-onetime initialization so that consumers can cache instances
+            //
+            if (key.Length != (int)blockSize / 8)
+            {
+                throw new ArgumentException("Key size should match block size");
+            }
+
+
+            this.BlockSize = blockSize;
+
+            //
+            // Set number of words rounds based on block size
+            //
+
+            _numWords = (int)BlockSize / sizeof(UInt64);
+
+            switch (BlockSize)
+            {
+
+                case ThreeFishBlockSize.BLOCKSIZE_256_BITS:
+                    this._rounds = ThreeFishRounds.ROUNDS_72;
+                    this.RotationConstants = Rdj_Nw_4;
+                    this.PermutationPi = Threefish.PI_I_Nw_4;
+                    break;
+                case ThreeFishBlockSize.BLOCKSIZE_512_BITS:
+                    this._rounds = ThreeFishRounds.ROUNDS_72;
+                    this.RotationConstants = Rdj_Nw_8;
+                    this.PermutationPi = Threefish.PI_I_Nw_8;
+                    break;
+                case ThreeFishBlockSize.BLOCKSIZE_1024_BITS:
+                    this._rounds = ThreeFishRounds.ROUNDS_80;
+                    this.RotationConstants = Rdj_Nw_16;
+                    this.PermutationPi = Threefish.PI_I_Nw_16;
+                    break;
+            }
+
+
+
+
+            //
+            // KeyWords is special in that it has an extra element kNw at the end
+            //
+            this.KeyWords = new UInt64[key.Length + 1];
+            Array.Copy(key, KeyWords, key.Length);
+
+
+
+            //
+            // Initialize Vd, Ed, fd and Ksd
+            //
+
+            _vd = new UInt64[_numWords];
+            _ed = new UInt64[_numWords];
+            _kdi = new UInt64[_numWords];
+            _fd = new UInt64[_numWords];
+
+            //
+            // Initialize ts values(as per section 3.3.2)
+            //
+            _ts[0] = tweak.low64;
+            _ts[1] = tweak.high64;
+            _ts[2] = _ts[0] ^ _ts[1];
+
+            //
+            // Initialize kNw (as per section 3.3.2). Already set to 2^64/3
+            //
+
+            for (int i = 0; i < _numWords; i++)
+            {
+                _kNw ^= KeyWords[i];
+            }
+            KeyWords[_numWords] = _kNw;
+
+        }
+
+        public void Encrypt(UInt64[] plainText, UInt64[] cipherText)
+        {
+
+            //
+            // Core workhorse where actual encryption gets done. We ask the caller to pass
+            // the ciphertext byte array so that they have an easier time of reusing it between calls
+            //
+
+
+            //
+            // Init v0,i = pi for i=0,...Nw-1
+            //
+            Array.Copy(plainText, _vd, _numWords);
+
+            //
+            //Loop correct number of rounds
+            //
+            for (UInt32 d = 0; d < (int)_rounds; d++)
+            {
+
+                //
+                // ed,i := (vd,i + kd/4,i) mod 2^64 if d mod 4==0
+                //      := (vd,i) otherwise
+                //
+
+                if (d % 4 == 0)
+                {
+
+                    SetSubKeyPerSchedule(d);
+                    for (int i = 0; i < _numWords; i++)
+                    {
+                        _ed[i] = _vd[i] + _kdi[i];
+                    }
+                }
+                else
+                {
+                    Array.Copy(_vd, _ed, _vd.Length);
+                }
+
+
+                //
+                //  y0,y1 for the Mix function. Why can't .NET return tuples yet?
+                //
+
+                for (UInt32 j = 0; j < (_numWords / 2); j++)
+                {
+                    UInt64 y0, y1;
+                    Mix(_ed[j * 2], _ed[j * 2 + 1], j, d, out y0, out y1);
+
+                    //
+                    // (fd,2j, fd,2j+1) := MIXd,j(ed,2j, ed,2j+1)
+                    //
+                    _fd[j * 2] = y0;
+                    _fd[j * 2 + 1] = y1;
+                }
+
+                for (int i = 0; i < _numWords; i++)
+                {
+                    //
+                    // vd+1,i := fd, pi(i)
+                    _vd[i] = _fd[this.PermutationPi[i]];
+                }
+
+            }
+
+            //
+            // Final schedule
+            //
+            SetSubKeyPerSchedule((UInt32)_rounds);
+
+            for (int i = 0; i < _numWords; i++)
+            {
+                //
+                // ci :=  (vNri + kNr/4, i) mod 2^64 for i=0,..., Nw-1
+                //
+                cipherText[i] = _vd[i] + _kdi[i];
+            }
+
+        }
+
+        private void Mix(UInt64 x0, UInt64 x1, UInt32 j, UInt32 d, out UInt64 y0, out UInt64 y1)
+        {
+
+            //
+            // Mix d,j as defined by section 3.3.1. It is defined as 
+            //
+            // y0 := ( x0 +x1) mod 2^64
+            // y1 := ( x1 <<< R (d mod 8) j xor y0
+            //
+
+            y0 = x0 + x1;
+            int rotation = RotationConstants[d % 8][j];
+
+            //
+            // Left rotate our UInt64. 
+            //
+
+            y1 = (x1 << rotation) | x1 >> (sizeof(UInt64) * 8 - rotation);
+            y1 ^= y0;
+
+
+        }
+
+
+        private void SetSubKeyPerSchedule(UInt32 currentRound)
+        {
+
+            //
+            //
+            // Implementation of core key schedule. Takes current round as input
+            // and sets ks,i
+            //
+
+            if (currentRound % 4 != 0)
+            {
+                throw new ArgumentException("Key schedule only on every 4th round");
+            }
+
+            UInt32 s = currentRound / 4;
+
+            for (int i = 0; i < _numWords; i++)
+            {
+
+                //
+                //
+                // First, fill in with key material. This expression is common to all
+                // i. This will take care of
+                //ks,i := k(s+1) mod (Nw +1) for i=0,...,Nw-4
+                //
+
+                _kdi[i] = KeyWords[(s + i) % (_numWords + 1)];
+
+                //
+                // ks,i := k(s+1) mod (Nw +1) + ts mod 3 for i=Nw-3
+                //
+
+                if (i == _numWords - 3)
+                {
+                    _kdi[i] = _kdi[i] + _ts[s % 3];
+                }
+
+                //
+                // ks,i := k(s+1) mod (Nw +1) + ts+1 mod 3 for i=Nw-2
+                //
+                if (i == _numWords - 2)
+                {
+                    _kdi[i] = _kdi[i] + _ts[(s + 1) % 3];
+                }
+
+                //
+                // ks,i := k(s+1) mod (Nw +1) + s for i=Nw-1
+                //
+                if (i == _numWords - 1)
+                {
+                    _kdi[i] = _kdi[i] + s;
+                }
+
+            }
+
+        }
+
+
+
+    }
+
+
+}

File HashIt/HashAlgorithms/Tiger.cs

+/* TigerManaged.cs
+ * 
+ * PROGRAMMER:    Jeffrey T. Darlington
+ * DATE:          September 21, 2007
+ * PROJECT:       WinHasher core library
+ * .NET VERSION:  2.0
+ * REQUIRES:      See using statements
+ * REQUIRED BY:   All WinHasher programs
+ * 
+ * This class implements the Tiger cryptographic hash (the 1995 192-bit version).  It is a
+ * subclass of System.Security.Cryptography.HashAlgorithm, so it should be usable as a
+ * drop-in hash engine with every other hash in WinHasher.
+ * 
+ * This is essentially a port of the Legion of the Bouncy Castle (http://www.bouncycastle.org/csharp/)
+ * implementation of Tiger, taking their .NET 1.1 code with their own APIs and rewrapping
+ * it as a subclass of the .NET 2.0 HashAlgorithm subclass.  As such, most of the code is actually
+ * pretty much the same as the BC original; all I've really done is hide some of their public
+ * methods that no longer apply and wrap the essential HashAlgorithm methods around them to fit
+ * in the .NET 2.0 interface.  The BC code is actually a port of the orginal Tiger code by
+ * Ross Anderson and Eli Biham.  See http://www.cs.technion.ac.il/~biham/Reports/Tiger
+ * Anderson and Biham's code is free to use; the Bouncy Castle code is copyrighted but
+ * released under a very permissive license (http://www.bouncycastle.org/csharp/licence.html).
+ * Some of the original comments are retained, with additional comments by me.
+ * 
+ * This program is Copyright 2007, Jeffrey T. Darlington.
+ * E-mail:  jeff@gpf-comics.com
+ * Web:     http://www.gpf-comics.com/
+ * 
+ * This program is free software; you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * 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.
+ * See theGNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Security.Cryptography;
+
+namespace HashIt
+{
+    public class Tiger : HashAlgorithm
+    {
+        private const int MyByteLength = 64;
+
+        /*
+        * S-Boxes.
+        */
+        private static readonly long[] t1 = {
+            unchecked((long) 0x02AAB17CF7E90C5EL)   /*    0 */,    unchecked((long) 0xAC424B03E243A8ECL)   /*    1 */,
+            unchecked((long) 0x72CD5BE30DD5FCD3L)   /*    2 */,    unchecked((long) 0x6D019B93F6F97F3AL)   /*    3 */,
+            unchecked((long) 0xCD9978FFD21F9193L)   /*    4 */,    unchecked((long) 0x7573A1C9708029E2L)   /*    5 */,
+            unchecked((long) 0xB164326B922A83C3L)   /*    6 */,    unchecked((long) 0x46883EEE04915870L)   /*    7 */,
+            unchecked((long) 0xEAACE3057103ECE6L)   /*    8 */,    unchecked((long) 0xC54169B808A3535CL)   /*    9 */,
+            unchecked((long) 0x4CE754918DDEC47CL)   /*   10 */,    unchecked((long) 0x0AA2F4DFDC0DF40CL)   /*   11 */,
+            unchecked((long) 0x10B76F18A74DBEFAL)   /*   12 */,    unchecked((long) 0xC6CCB6235AD1AB6AL)   /*   13 */,
+            unchecked((long) 0x13726121572FE2FFL)   /*   14 */,    unchecked((long) 0x1A488C6F199D921EL)   /*   15 */,
+            unchecked((long) 0x4BC9F9F4DA0007CAL)   /*   16 */,    unchecked((long) 0x26F5E6F6E85241C7L)   /*   17 */,
+            unchecked((long) 0x859079DBEA5947B6L)   /*   18 */,    unchecked((long) 0x4F1885C5C99E8C92L)   /*   19 */,
+            unchecked((long) 0xD78E761EA96F864BL)   /*   20 */,    unchecked((long) 0x8E36428C52B5C17DL)   /*   21 */,
+            unchecked((long) 0x69CF6827373063C1L)   /*   22 */,    unchecked((long) 0xB607C93D9BB4C56EL)   /*   23 */,
+            unchecked((long) 0x7D820E760E76B5EAL)   /*   24 */,    unchecked((long) 0x645C9CC6F07FDC42L)   /*   25 */,
+            unchecked((long) 0xBF38A078243342E0L)   /*   26 */,    unchecked((long) 0x5F6B343C9D2E7D04L)   /*   27 */,
+            unchecked((long) 0xF2C28AEB600B0EC6L)   /*   28 */,    unchecked((long) 0x6C0ED85F7254BCACL)   /*   29 */,
+            unchecked((long) 0x71592281A4DB4FE5L)   /*   30 */,    unchecked((long) 0x1967FA69CE0FED9FL)   /*   31 */,
+            unchecked((long) 0xFD5293F8B96545DBL)   /*   32 */,    unchecked((long) 0xC879E9D7F2A7600BL)   /*   33 */,
+            unchecked((long) 0x860248920193194EL)   /*   34 */,    unchecked((long) 0xA4F9533B2D9CC0B3L)   /*   35 */,
+            unchecked((long) 0x9053836C15957613L)   /*   36 */,    unchecked((long) 0xDB6DCF8AFC357BF1L)   /*   37 */,
+            unchecked((long) 0x18BEEA7A7A370F57L)   /*   38 */,    unchecked((long) 0x037117CA50B99066L)   /*   39 */,
+            unchecked((long) 0x6AB30A9774424A35L)   /*   40 */,    unchecked((long) 0xF4E92F02E325249BL)   /*   41 */,
+            unchecked((long) 0x7739DB07061CCAE1L)   /*   42 */,    unchecked((long) 0xD8F3B49CECA42A05L)   /*   43 */,
+            unchecked((long) 0xBD56BE3F51382F73L)   /*   44 */,    unchecked((long) 0x45FAED5843B0BB28L)   /*   45 */,
+            unchecked((long) 0x1C813D5C11BF1F83L)   /*   46 */,    unchecked((long) 0x8AF0E4B6D75FA169L)   /*   47 */,
+            unchecked((long) 0x33EE18A487AD9999L)   /*   48 */,    unchecked((long) 0x3C26E8EAB1C94410L)   /*   49 */,
+            unchecked((long) 0xB510102BC0A822F9L)   /*   50 */,    unchecked((long) 0x141EEF310CE6123BL)   /*   51 */,
+            unchecked((long) 0xFC65B90059DDB154L)   /*   52 */,    unchecked((long) 0xE0158640C5E0E607L)   /*   53 */,
+            unchecked((long) 0x884E079826C3A3CFL)   /*   54 */,    unchecked((long) 0x930D0D9523C535FDL)   /*   55 */,
+            unchecked((long) 0x35638D754E9A2B00L)   /*   56 */,    unchecked((long) 0x4085FCCF40469DD5L)   /*   57 */,
+            unchecked((long) 0xC4B17AD28BE23A4CL)   /*   58 */,    unchecked((long) 0xCAB2F0FC6A3E6A2EL)   /*   59 */,
+            unchecked((long) 0x2860971A6B943FCDL)   /*   60 */,    unchecked((long) 0x3DDE6EE212E30446L)   /*   61 */,
+            unchecked((long) 0x6222F32AE01765AEL)   /*   62 */,    unchecked((long) 0x5D550BB5478308FEL)   /*   63 */,
+            unchecked((long) 0xA9EFA98DA0EDA22AL)   /*   64 */,    unchecked((long) 0xC351A71686C40DA7L)   /*   65 */,
+            unchecked((long) 0x1105586D9C867C84L)   /*   66 */,    unchecked((long) 0xDCFFEE85FDA22853L)   /*   67 */,
+            unchecked((long) 0xCCFBD0262C5EEF76L)   /*   68 */,    unchecked((long) 0xBAF294CB8990D201L)   /*   69 */,
+            unchecked((long) 0xE69464F52AFAD975L)   /*   70 */,    unchecked((long) 0x94B013AFDF133E14L)   /*   71 */,
+            unchecked((long) 0x06A7D1A32823C958L)   /*   72 */,    unchecked((long) 0x6F95FE5130F61119L)   /*   73 */,
+            unchecked((long) 0xD92AB34E462C06C0L)   /*   74 */,    unchecked((long) 0xED7BDE33887C71D2L)   /*   75 */,
+            unchecked((long) 0x79746D6E6518393EL)   /*   76 */,    unchecked((long) 0x5BA419385D713329L)   /*   77 */,
+            unchecked((long) 0x7C1BA6B948A97564L)   /*   78 */,    unchecked((long) 0x31987C197BFDAC67L)   /*   79 */,
+            unchecked((long) 0xDE6C23C44B053D02L)   /*   80 */,    unchecked((long) 0x581C49FED002D64DL)   /*   81 */,
+            unchecked((long) 0xDD474D6338261571L)   /*   82 */,    unchecked((long) 0xAA4546C3E473D062L)   /*   83 */,
+            unchecked((long) 0x928FCE349455F860L)   /*   84 */,    unchecked((long) 0x48161BBACAAB94D9L)   /*   85 */,
+            unchecked((long) 0x63912430770E6F68L)   /*   86 */,    unchecked((long) 0x6EC8A5E602C6641CL)   /*   87 */,
+            unchecked((long) 0x87282515337DDD2BL)   /*   88 */,    unchecked((long) 0x2CDA6B42034B701BL)   /*   89 */,
+            unchecked((long) 0xB03D37C181CB096DL)   /*   90 */,    unchecked((long) 0xE108438266C71C6FL)   /*   91 */,
+            unchecked((long) 0x2B3180C7EB51B255L)   /*   92 */,    unchecked((long) 0xDF92B82F96C08BBCL)   /*   93 */,
+            unchecked((long) 0x5C68C8C0A632F3BAL)   /*   94 */,    unchecked((long) 0x5504CC861C3D0556L)   /*   95 */,
+            unchecked((long) 0xABBFA4E55FB26B8FL)   /*   96 */,    unchecked((long) 0x41848B0AB3BACEB4L)   /*   97 */,
+            unchecked((long) 0xB334A273AA445D32L)   /*   98 */,    unchecked((long) 0xBCA696F0A85AD881L)   /*   99 */,
+            unchecked((long) 0x24F6EC65B528D56CL)   /*  100 */,    unchecked((long) 0x0CE1512E90F4524AL)   /*  101 */,
+            unchecked((long) 0x4E9DD79D5506D35AL)   /*  102 */,    unchecked((long) 0x258905FAC6CE9779L)   /*  103 */,
+            unchecked((long) 0x2019295B3E109B33L)   /*  104 */,    unchecked((long) 0xF8A9478B73A054CCL)   /*  105 */,
+            unchecked((long) 0x2924F2F934417EB0L)   /*  106 */,    unchecked((long) 0x3993357D536D1BC4L)   /*  107 */,
+            unchecked((long) 0x38A81AC21DB6FF8BL)   /*  108 */,    unchecked((long) 0x47C4FBF17D6016BFL)   /*  109 */,
+            unchecked((long) 0x1E0FAADD7667E3F5L)   /*  110 */,    unchecked((long) 0x7ABCFF62938BEB96L)   /*  111 */,
+            unchecked((long) 0xA78DAD948FC179C9L)   /*  112 */,    unchecked((long) 0x8F1F98B72911E50DL)   /*  113 */,
+            unchecked((long) 0x61E48EAE27121A91L)   /*  114 */,    unchecked((long) 0x4D62F7AD31859808L)   /*  115 */,
+            unchecked((long) 0xECEBA345EF5CEAEBL)   /*  116 */,    unchecked((long) 0xF5CEB25EBC9684CEL)   /*  117 */,
+            unchecked((long) 0xF633E20CB7F76221L)   /*  118 */,    unchecked((long) 0xA32CDF06AB8293E4L)   /*  119 */,
+            unchecked((long) 0x985A202CA5EE2CA4L)   /*  120 */,    unchecked((long) 0xCF0B8447CC8A8FB1L)   /*  121 */,
+            unchecked((long) 0x9F765244979859A3L)   /*  122 */,    unchecked((long) 0xA8D516B1A1240017L)   /*  123 */,
+            unchecked((long) 0x0BD7BA3EBB5DC726L)   /*  124 */,    unchecked((long) 0xE54BCA55B86ADB39L)   /*  125 */,
+            unchecked((long) 0x1D7A3AFD6C478063L)   /*  126 */,    unchecked((long) 0x519EC608E7669EDDL)   /*  127 */,
+            unchecked((long) 0x0E5715A2D149AA23L)   /*  128 */,    unchecked((long) 0x177D4571848FF194L)   /*  129 */,
+            unchecked((long) 0xEEB55F3241014C22L)   /*  130 */,    unchecked((long) 0x0F5E5CA13A6E2EC2L)   /*  131 */,
+            unchecked((long) 0x8029927B75F5C361L)   /*  132 */,    unchecked((long) 0xAD139FABC3D6E436L)   /*  133 */,
+            unchecked((long) 0x0D5DF1A94CCF402FL)   /*  134 */,    unchecked((long) 0x3E8BD948BEA5DFC8L)   /*  135 */,
+            unchecked((long) 0xA5A0D357BD3FF77EL)   /*  136 */,    unchecked((long) 0xA2D12E251F74F645L)   /*  137 */,
+            unchecked((long) 0x66FD9E525E81A082L)   /*  138 */,    unchecked((long) 0x2E0C90CE7F687A49L)   /*  139 */,
+            unchecked((long) 0xC2E8BCBEBA973BC5L)   /*  140 */,    unchecked((long) 0x000001BCE509745FL)   /*  141 */,
+            unchecked((long) 0x423777BBE6DAB3D6L)   /*  142 */,    unchecked((long) 0xD1661C7EAEF06EB5L)   /*  143 */,
+            unchecked((long) 0xA1781F354DAACFD8L)   /*  144 */,    unchecked((long) 0x2D11284A2B16AFFCL)   /*  145 */,
+            unchecked((long) 0xF1FC4F67FA891D1FL)   /*  146 */,    unchecked((long) 0x73ECC25DCB920ADAL)   /*  147 */,
+            unchecked((long) 0xAE610C22C2A12651L)   /*  148 */,    unchecked((long) 0x96E0A810D356B78AL)   /*  149 */,
+            unchecked((long) 0x5A9A381F2FE7870FL)   /*  150 */,    unchecked((long) 0xD5AD62EDE94E5530L)   /*  151 */,
+            unchecked((long) 0xD225E5E8368D1427L)   /*  152 */,    unchecked((long) 0x65977B70C7AF4631L)   /*  153 */,
+            unchecked((long) 0x99F889B2DE39D74FL)   /*  154 */,    unchecked((long) 0x233F30BF54E1D143L)   /*  155 */,
+            unchecked((long) 0x9A9675D3D9A63C97L)   /*  156 */,    unchecked((long) 0x5470554FF334F9A8L)   /*  157 */,
+            unchecked((long) 0x166ACB744A4F5688L)   /*  158 */,    unchecked((long) 0x70C74CAAB2E4AEADL)   /*  159 */,
+            unchecked((long) 0xF0D091646F294D12L)   /*  160 */,    unchecked((long) 0x57B82A89684031D1L)   /*  161 */,
+            unchecked((long) 0xEFD95A5A61BE0B6BL)   /*  162 */,    unchecked((long) 0x2FBD12E969F2F29AL)   /*  163 */,
+            unchecked((long) 0x9BD37013FEFF9FE8L)   /*  164 */,    unchecked((long) 0x3F9B0404D6085A06L)   /*  165 */,
+            unchecked((long) 0x4940C1F3166CFE15L)   /*  166 */,    unchecked((long) 0x09542C4DCDF3DEFBL)   /*  167 */,
+            unchecked((long) 0xB4C5218385CD5CE3L)   /*  168 */,    unchecked((long) 0xC935B7DC4462A641L)   /*  169 */,
+            unchecked((long) 0x3417F8A68ED3B63FL)   /*  170 */,    unchecked((long) 0xB80959295B215B40L)   /*  171 */,
+            unchecked((long) 0xF99CDAEF3B8C8572L)   /*  172 */,    unchecked((long) 0x018C0614F8FCB95DL)   /*  173 */,
+            unchecked((long) 0x1B14ACCD1A3ACDF3L)   /*  174 */,    unchecked((long) 0x84D471F200BB732DL)   /*  175 */,
+            unchecked((long) 0xC1A3110E95E8DA16L)   /*  176 */,    unchecked((long) 0x430A7220BF1A82B8L)   /*  177 */,
+            unchecked((long) 0xB77E090D39DF210EL)   /*  178 */,    unchecked((long) 0x5EF4BD9F3CD05E9DL)   /*  179 */,
+            unchecked((long) 0x9D4FF6DA7E57A444L)   /*  180 */,    unchecked((long) 0xDA1D60E183D4A5F8L)   /*  181 */,
+            unchecked((long) 0xB287C38417998E47L)   /*  182 */,    unchecked((long) 0xFE3EDC121BB31886L)   /*  183 */,
+            unchecked((long) 0xC7FE3CCC980CCBEFL)   /*  184 */,    unchecked((long) 0xE46FB590189BFD03L)   /*  185 */,
+            unchecked((long) 0x3732FD469A4C57DCL)   /*  186 */,    unchecked((long) 0x7EF700A07CF1AD65L)   /*  187 */,
+            unchecked((long) 0x59C64468A31D8859L)   /*  188 */,    unchecked((long) 0x762FB0B4D45B61F6L)   /*  189 */,
+            unchecked((long) 0x155BAED099047718L)   /*  190 */,    unchecked((long) 0x68755E4C3D50BAA6L)   /*  191 */,
+            unchecked((long) 0xE9214E7F22D8B4DFL)   /*  192 */,    unchecked((long) 0x2ADDBF532EAC95F4L)   /*  193 */,
+            unchecked((long) 0x32AE3909B4BD0109L)   /*  194 */,    unchecked((long) 0x834DF537B08E3450L)   /*  195 */,
+            unchecked((long) 0xFA209DA84220728DL)   /*  196 */,    unchecked((long) 0x9E691D9B9EFE23F7L)   /*  197 */,
+            unchecked((long) 0x0446D288C4AE8D7FL)   /*  198 */,    unchecked((long) 0x7B4CC524E169785BL)   /*  199 */,
+            unchecked((long) 0x21D87F0135CA1385L)   /*  200 */,    unchecked((long) 0xCEBB400F137B8AA5L)   /*  201 */,
+            unchecked((long) 0x272E2B66580796BEL)   /*  202 */,    unchecked((long) 0x3612264125C2B0DEL)   /*  203 */,
+            unchecked((long) 0x057702BDAD1EFBB2L)   /*  204 */,    unchecked((long) 0xD4BABB8EACF84BE9L)   /*  205 */,
+            unchecked((long) 0x91583139641BC67BL)   /*  206 */,    unchecked((long) 0x8BDC2DE08036E024L)   /*  207 */,
+            unchecked((long) 0x603C8156F49F68EDL)   /*  208 */,    unchecked((long) 0xF7D236F7DBEF5111L)   /*  209 */,
+            unchecked((long) 0x9727C4598AD21E80L)   /*  210 */,    unchecked((long) 0xA08A0896670A5FD7L)   /*  211 */,
+            unchecked((long) 0xCB4A8F4309EBA9CBL)   /*  212 */,    unchecked((long) 0x81AF564B0F7036A1L)   /*  213 */,
+            unchecked((long) 0xC0B99AA778199ABDL)   /*  214 */,    unchecked((long) 0x959F1EC83FC8E952L)   /*  215 */,
+            unchecked((long) 0x8C505077794A81B9L)   /*  216 */,    unchecked((long) 0x3ACAAF8F056338F0L)   /*  217 */,
+            unchecked((long) 0x07B43F50627A6778L)   /*  218 */,    unchecked((long) 0x4A44AB49F5ECCC77L)   /*  219 */,
+            unchecked((long) 0x3BC3D6E4B679EE98L)   /*  220 */,    unchecked((long) 0x9CC0D4D1CF14108CL)   /*  221 */,
+            unchecked((long) 0x4406C00B206BC8A0L)   /*  222 */,    unchecked((long) 0x82A18854C8D72D89L)   /*  223 */,
+            unchecked((long) 0x67E366B35C3C432CL)   /*  224 */,    unchecked((long) 0xB923DD61102B37F2L)   /*  225 */,
+            unchecked((long) 0x56AB2779D884271DL)   /*  226 */,    unchecked((long) 0xBE83E1B0FF1525AFL)   /*  227 */,
+            unchecked((long) 0xFB7C65D4217E49A9L)   /*  228 */,    unchecked((long) 0x6BDBE0E76D48E7D4L)   /*  229 */,
+            unchecked((long) 0x08DF828745D9179EL)   /*  230 */,    unchecked((long) 0x22EA6A9ADD53BD34L)   /*  231 */,
+            unchecked((long) 0xE36E141C5622200AL)   /*  232 */,    unchecked((long) 0x7F805D1B8CB750EEL)   /*  233 */,
+            unchecked((long) 0xAFE5C7A59F58E837L)   /*  234 */,    unchecked((long) 0xE27F996A4FB1C23CL)   /*  235 */,
+            unchecked((long) 0xD3867DFB0775F0D0L)   /*  236 */,    unchecked((long) 0xD0E673DE6E88891AL)   /*  237 */,
+            unchecked((long) 0x123AEB9EAFB86C25L)   /*  238 */,    unchecked((long) 0x30F1D5D5C145B895L)   /*  239 */,
+            unchecked((long) 0xBB434A2DEE7269E7L)   /*  240 */,    unchecked((long) 0x78CB67ECF931FA38L)   /*  241 */,
+            unchecked((long) 0xF33B0372323BBF9CL)   /*  242 */,    unchecked((long) 0x52D66336FB279C74L)   /*  243 */,
+            unchecked((long) 0x505F33AC0AFB4EAAL)   /*  244 */,    unchecked((long) 0xE8A5CD99A2CCE187L)   /*  245 */,
+            unchecked((long) 0x534974801E2D30BBL)   /*  246 */,    unchecked((long) 0x8D2D5711D5876D90L)   /*  247 */,
+            unchecked((long) 0x1F1A412891BC038EL)   /*  248 */,    unchecked((long) 0xD6E2E71D82E56648L)   /*  249 */,
+            unchecked((long) 0x74036C3A497732B7L)   /*  250 */,    unchecked((long) 0x89B67ED96361F5ABL)   /*  251 */,
+            unchecked((long) 0xFFED95D8F1EA02A2L)   /*  252 */,    unchecked((long) 0xE72B3BD61464D43DL)   /*  253 */,
+            unchecked((long) 0xA6300F170BDC4820L)   /*  254 */,    unchecked((long) 0xEBC18760ED78A77AL)   /*  255 */,
+        };
+
+        private static readonly long[] t2 = {
+            unchecked((long) 0xE6A6BE5A05A12138L)   /*  256 */,    unchecked((long) 0xB5A122A5B4F87C98L)   /*  257 */,
+            unchecked((long) 0x563C6089140B6990L)   /*  258 */,    unchecked((long) 0x4C46CB2E391F5DD5L)   /*  259 */,
+            unchecked((long) 0xD932ADDBC9B79434L)   /*  260 */,    unchecked((long) 0x08EA70E42015AFF5L)   /*  261 */,
+            unchecked((long) 0xD765A6673E478CF1L)   /*  262 */,    unchecked((long) 0xC4FB757EAB278D99L)   /*  263 */,
+            unchecked((long) 0xDF11C6862D6E0692L)   /*  264 */,    unchecked((long) 0xDDEB84F10D7F3B16L)   /*  265 */,
+            unchecked((long) 0x6F2EF604A665EA04L)   /*  266 */,    unchecked((long) 0x4A8E0F0FF0E0DFB3L)   /*  267 */,
+            unchecked((long) 0xA5EDEEF83DBCBA51L)   /*  268 */,    unchecked((long) 0xFC4F0A2A0EA4371EL)   /*  269 */,
+            unchecked((long) 0xE83E1DA85CB38429L)   /*  270 */,    unchecked((long) 0xDC8FF882BA1B1CE2L)   /*  271 */,
+            unchecked((long) 0xCD45505E8353E80DL)   /*  272 */,    unchecked((long) 0x18D19A00D4DB0717L)   /*  273 */,
+            unchecked((long) 0x34A0CFEDA5F38101L)   /*  274 */,    unchecked((long) 0x0BE77E518887CAF2L)   /*  275 */,
+            unchecked((long) 0x1E341438B3C45136L)   /*  276 */,    unchecked((long) 0xE05797F49089CCF9L)   /*  277 */,
+            unchecked((long) 0xFFD23F9DF2591D14L)   /*  278 */,    unchecked((long) 0x543DDA228595C5CDL)   /*  279 */,
+            unchecked((long) 0x661F81FD99052A33L)   /*  280 */,    unchecked((long) 0x8736E641DB0F7B76L)   /*  281 */,
+            unchecked((long) 0x15227725418E5307L)   /*  282 */,    unchecked((long) 0xE25F7F46162EB2FAL)   /*  283 */,
+            unchecked((long) 0x48A8B2126C13D9FEL)   /*  284 */,    unchecked((long) 0xAFDC541792E76EEAL)   /*  285 */,
+            unchecked((long) 0x03D912BFC6D1898FL)   /*  286 */,    unchecked((long) 0x31B1AAFA1B83F51BL)   /*  287 */,
+            unchecked((long) 0xF1AC2796E42AB7D9L)   /*  288 */,    unchecked((long) 0x40A3A7D7FCD2EBACL)   /*  289 */,
+            unchecked((long) 0x1056136D0AFBBCC5L)   /*  290 */,    unchecked((long) 0x7889E1DD9A6D0C85L)   /*  291 */,