1 /******************************************************************************
2 
3     TODO: move module to ocean.util.digest
4 
5     Copyright:
6         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
7         All rights reserved.
8 
9     License:
10         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
11         Alternatively, this file may be distributed under the terms of the Tango
12         3-Clause BSD License (see LICENSE_BSD.txt for details).
13 
14 *******************************************************************************/
15 
16 module  ocean.io.digest.Fnv1;
17 
18 
19 
20 import ocean.meta.types.Qualifiers;
21 import ocean.util.digest.Digest;
22 
23 import ocean.core.ByteSwap;
24 
25 version (unittest) import ocean.core.Test;
26 
27 
28 /******************************************************************************
29 
30     template for creating FNV magic constants and endianness, depending on
31     if 32bit (uint) or 64bit (ulong) are used.
32 
33     Params:
34         T = Type of hash to use, should be `uint` or `ulong`, or any alias
35             to them. Defaults to `hash_t`, which is a D alias to `size_t`.
36 
37 *******************************************************************************/
38 
39 public template Fnv1Const ( T = hash_t )
40 {
41     /**************************************************************************
42 
43         FNV magic constants and endianness
44 
45      **************************************************************************/
46 
47     public alias T DigestType;
48 
49     static if (is (DigestType == uint))
50     {
51         public static immutable DigestType PRIME = 0x0100_0193; // 32 bit prime
52         public static immutable DigestType INIT  = 0x811C_9DC5; // 32 bit inital digest
53         public alias ByteSwap.swap32 toBigEnd;
54     }
55     else static if (is (DigestType == ulong))
56     {
57         public static immutable DigestType PRIME = 0x0000_0100_0000_01B3; // 64 bit prime
58         public static immutable DigestType INIT  = 0xCBF2_9CE4_8422_2325; // 64 bit inital digest
59         public alias ByteSwap.swap64 toBigEnd;
60     }
61     /*
62     // be prepared for the day when Walter introduces cent...
63     else static if (is (DigestType == ucent))
64     {
65         public const DigestType PRIME = 0x0000_0000_0100_0000_0000_0000_0000_013B; // 128 bit prime
66         public const DigestType PRIME = 0x6C62_272E_07BB_0142_62B8_2175_6295_C58D; // 128 bit inital digest
67     }
68     */
69     else static assert (false, "type '" ~ DigestType.stringof ~
70                                "' is not supported, only uint and ulong");
71 }
72 
73 
74 /******************************************************************************
75 
76     Convenience aliases for 32-bit and 64-bit Fnv1 class template instances.
77     Must be defined after Fnv1Const to avoid DMD errors
78 
79 *******************************************************************************/
80 
81 public alias Fnv1Generic!(true)         Fnv1a;
82 public alias Fnv1Generic!(true,  uint)  Fnv1a32;
83 public alias Fnv1Generic!(true,  ulong) Fnv1a64;
84 
85 
86 /******************************************************************************
87 
88     Compile time fnv1a hash function, calculates a hash value of type T where T
89     must be uint or ulong.
90 
91     Convenience aliases for 32 bit (T = uint) or 64 bit (T = ulong) hashes are
92     defined below. They have to appear after this template definition because
93     DMD can currently (v1.075) not handle forward aliases in this case.
94 
95     Params:
96         T = Type of hash to use, should be `uint` or `ulong`, or any alias
97             to them. Defaults to `hash_t`, which is a D alias to `size_t`.
98 
99 *******************************************************************************/
100 
101 public template StaticFnv1a ( T = hash_t )
102 {
103     /***************************************************************************
104 
105         Calculates the Fnv1a hash value of type T from input.
106 
107     ***************************************************************************/
108 
109     public template Fnv1a ( istring input )
110     {
111         public static immutable Fnv1a = Fnv1a!(Fnv1Const!(T).INIT, input);
112     }
113 
114     /***************************************************************************
115 
116         Calculates the Fnv1a hash value of type T from input using hash as
117         initial hash value.
118 
119     ***************************************************************************/
120 
121     public template Fnv1a ( T hash, istring input )
122     {
123         static if ( input.length )
124         {
125             public static immutable Fnv1a = Fnv1a!((hash ^ input[0]) * Fnv1Const!(T).PRIME, input[1 .. $]);
126         }
127         else
128         {
129             public static immutable Fnv1a = hash;
130         }
131     }
132 }
133 
134 
135 /******************************************************************************
136 
137     Aliases for Fnv1 32 and 64 bit magic constants.
138 
139 *******************************************************************************/
140 
141 public alias Fnv1Const!(uint)  Fnv132Const;
142 public alias Fnv1Const!(ulong) Fnv164Const;
143 
144 /******************************************************************************
145 
146     Templates for compile-time FNV1a hashing.
147 
148 *******************************************************************************/
149 
150 public template StaticFnv1a32 ( istring input )
151 {
152     public static immutable StaticFnv1a32 = StaticFnv1a!(uint).Fnv1a!(input);
153 }
154 
155 public template StaticFnv1a32 ( uint hash, istring input )
156 {
157     public static immutable StaticFnv1a32 = StaticFnv1a!(uint).Fnv1a!(hash, input);
158 }
159 
160 public template StaticFnv1a64 ( istring input )
161 {
162     public static immutable StaticFnv1a64 = StaticFnv1a!(ulong).Fnv1a!(input);
163 }
164 
165 public template StaticFnv1a64 ( ulong hash, istring input )
166 {
167     public static immutable StaticFnv1a64 = StaticFnv1a!(ulong).Fnv1a!(hash, input);
168 }
169 
170 
171 /******************************************************************************
172 
173     abstract Fnv1 digest class
174 
175 *******************************************************************************/
176 
177 public abstract class FnvDigest : Digest
178 {
179     /**************************************************************************
180 
181         Simply returns the digest as an ulong independently of the digest size
182         and reset the internal state.
183 
184         Returns:
185              digest
186 
187      **************************************************************************/
188 
189     public abstract ulong ulongDigest ( );
190 }
191 
192 
193 /*******************************************************************************
194 
195         Fowler / Noll / Vo (FNV) 1/1a Hash Module
196 
197         Very fast hashing algorithm implementation with support for 32/64 bit
198         hashes.
199         This modules implements two versions of FNV1: FNV1 and FNV1a. The
200         difference is extremely slight and Noll himself says:
201 
202             "Some people use FNV1a instead of FNV1 because they see slightly
203             better dispersion for tiny (<4 octets) chunks of memory. Either
204             FNV-1 or FNV-1a make a fine hash."
205 
206             (cited from http://www.isthe.com/chongo/tech/comp/fnv/)
207 
208 
209         The FNV1A template parameter selects FNV1a if set to true on
210         instantiation or FNV1 otherwise. It is recommended to use the
211         Fnv1XX/Fnv1aXX aliases.
212 
213         Fnv1 and Fnv1a (without 32/64 suffix) use the native machine data word
214         width.
215 
216         32bit ~ 3704333.44 hash/sec
217         64bit ~ 1728119.76 hash/sec
218 
219         --
220 
221         Usage
222 
223         It is recommended to use these Fnv1 class convenience aliases:
224 
225          - Fnv1 for FNV1 digests of the machine's native width
226          - Fnv1a for FNV1a digests of the machine's native width
227 
228          - Fnv132 for 32-bit FNV1 digests
229          - Fnv1a32 for 32-bit FNV1a digests
230 
231          - Fnv164 for 64-bit FNV1 digests
232          - Fnv1a64 for 64-bit FNV1a digests
233 
234         Example 1: Generating FNV1 digests using class instances
235 
236         ---
237 
238             import ocean.io.digest.Fnv1;
239 
240             auto fnv1   = new Fnv1;
241             auto fnv132 = new Fnv132;
242             auto fnv164 = new Fnv164;
243 
244             auto hello = "Hello World!";
245 
246             fnv1.update(hello);
247             fnv132.update(hello);
248             fnv164.update(hello);
249 
250             auto hash   = fnv1.hexDigest();
251             auto hash32 = fnv132.hexDigest();
252             auto hash64 = fnv164.hexDigest();
253 
254         ---
255 
256         Example 2: Generating FNV1a digests using the static fnv1() method
257 
258         ---
259 
260             import ocean.io.digest.Fnv;
261 
262             auto hello = "Hello World!";
263 
264             size_t hash   = Fnv1a(hello);       // size_t uses the native machine data word width
265             uint   hash32 = Fnv1a32(hello);
266             ulong  hash64 = Fnv1a64(hello);
267 
268         ---
269 
270         --
271 
272         We should use this hash algorithm in combination with this consistent
273         hash algorithm in order to build a distributed hash table (DTH)
274 
275         http://www.audioscrobbler.net/development/ketama/
276         svn://svn.audioscrobbler.net/misc/ketama/
277         http://pdos.csail.mit.edu/chord/
278 
279         --
280 
281         References
282 
283         http://www.isthe.com/chongo/tech/comp/fnv/
284         http://www.azillionmonkeys.com/qed/hash.html
285         http://www.azillionmonkeys.com/qed/hash.c
286         http://www.digitalmars.com/d/2.0/htomodule.html
287 
288         http://www.team5150.com/~andrew/blog/2007/03/breaking_superfasthash.html
289         http://www.team5150.com/~andrew/blog/2007/03/when_bad_hashing_means_good_caching.html
290         http://www.azillionmonkeys.com/qed/hash.html
291 
292 *******************************************************************************/
293 
294 public class Fnv1Generic ( bool FNV1A = false, T = hash_t ) : FnvDigest
295 {
296     /**************************************************************************
297 
298         DigestType type alias
299 
300      **************************************************************************/
301 
302     mixin Fnv1Const!(T);
303 
304     /**************************************************************************
305 
306         Binary digest length and hexadecimal digest string length constants
307 
308      **************************************************************************/
309 
310     public static immutable DIGEST_LENGTH = DigestType.sizeof;
311     public static immutable HEXDGT_LENGTH = DIGEST_LENGTH * 2;
312 
313     public alias char[HEXDGT_LENGTH] HexDigest;
314 
315     /**************************************************************************
316 
317         This alias for chainable methods
318 
319      **************************************************************************/
320 
321     public alias typeof (this) This;
322 
323     /**************************************************************************
324 
325         Endianness aware integer to byte array converter
326 
327         Usage:
328 
329         ---
330 
331              Fnv32.BinConvert bc;
332 
333              ubyte[] binstr = bc(0xAFFE4711);
334 
335              // binstr now is [0xAF, 0xFE, 0x47, 0x11]
336 
337         ---
338 
339      **************************************************************************/
340 
341      public union BinConvert
342      {
343          public alias ubyte[DIGEST_LENGTH] BinString;
344 
345          /* members */
346 
347          public BinString array;
348 
349          public DigestType value;
350 
351          /* cast "value" from integer type "DigestType" to binary string type "BinString"
352             considering machine byte order (endianness) */
353 
354          public ubyte[] opCall ( DigestType value )
355          {
356              this.value = value;
357 
358              version (LittleEndian) toBigEnd(array);
359 
360              return array.dup;
361          }
362      };
363 
364 
365     /**************************************************************************
366 
367         class properties
368 
369      **************************************************************************/
370 
371     private DigestType digest = this.INIT;
372 
373 
374     /**************************************************************************
375 
376         Tango DigestType class methods
377 
378      **************************************************************************/
379 
380 
381     /**************************************************************************
382 
383         Processes data
384 
385         Remarks:
386               Updates the hash algorithm state with new data
387 
388      **************************************************************************/
389 
390     public override This update ( const(void)[] data )
391     {
392         this.digest = this.fnv1(data, this.digest);
393 
394         return this;
395     }
396 
397 
398     /**************************************************************************
399 
400         Computes the digest and resets the state
401 
402         Params:
403             buffer = a buffer can be supplied for the digest to be
404                      written to
405 
406         Remarks:
407             This method is endianness-aware: The returned array has always the
408             least-order byte at byte [0] (big endian).
409 
410             If the buffer is not large enough to hold the
411             digest, a new buffer is allocated and returned.
412             The algorithm state is always reset after a call to
413             binaryDigest. Use the digestSize method to find out how
414             large the buffer has to be.
415 
416     ***************************************************************************/
417 
418     public override ubyte[] binaryDigest( ubyte[] buffer = null )
419     {
420         scope(exit) this.reset();
421 
422         BinConvert bc;
423 
424         bc(this.digest);
425 
426         if ( buffer )
427         {
428             buffer.length = this.digestSize();
429 
430             foreach (i, d; bc.array)
431             {
432                 buffer[i] = d;
433             }
434         }
435 
436         return buffer? buffer: bc.array.dup;
437     }
438 
439 
440     /**************************************************************************
441 
442         Returns the size in bytes of the digest
443 
444         Returns:
445           the size of the digest in bytes
446 
447         Remarks:
448           Returns the size of the digest.
449 
450     ***************************************************************************/
451 
452     public override uint digestSize ( )
453     {
454         return this.DIGEST_LENGTH;
455     }
456 
457 
458     /**************************************************************************
459 
460         extension class methods (in addition to the DigestType standard methods)
461 
462      **************************************************************************/
463 
464 
465     /**************************************************************************
466 
467         Resets the state
468 
469         Returns:
470              this instance
471 
472      ***************************************************************************/
473 
474     public This reset ( )
475     {
476         this.digest = this.INIT;
477 
478         return this;
479     }
480 
481 
482     /**************************************************************************
483 
484         Simply returns the digest
485 
486         Returns:
487              digest
488 
489      **************************************************************************/
490 
491     public DigestType getDigest ( )
492     {
493         return this.digest;
494     }
495 
496 
497     /**************************************************************************
498 
499         Simply returns the digest as an ulong independently of the digest size
500         and reset the internal state.
501 
502         Returns:
503              digest
504 
505      **************************************************************************/
506 
507     public override ulong ulongDigest ( )
508     {
509         ulong d = this.digest;
510         this.reset();
511         return d;
512     }
513 
514 
515     /**************************************************************************
516 
517         Core methods
518 
519      **************************************************************************/
520 
521 
522 
523     /**************************************************************************
524 
525         Calculates a FNV1/FNV1a digest from data. data are processed in
526         octet/byte-wise manner.
527 
528         Usage:
529 
530         ---
531 
532              import ocean.io.digest.Fnv;
533 
534              auto data = "sociomantic";
535 
536              uint  digest32 = Fnv32.fnv1(data);
537              ulong digest64 = Fnv64.fnv1(data);
538 
539         ---
540 
541         Params:
542              data =   data to digest
543              digest = initial digest; defaults to the magic 32 bit or 64 bit
544                       initial value, according to DigestType
545 
546         Returns:
547              resulting digest
548 
549      **************************************************************************/
550 
551     public static DigestType fnv1 ( U ) ( U data, DigestType digest = INIT )
552     {
553         const(ubyte)[] data_;
554 
555         static if (is (Unqual!(U) : ubyte[]))
556         {
557             data_ = data;
558         }
559         else static if (is (U V : V[]))
560         {
561             static if (V.sizeof == 1)
562             {
563                 data_ = cast(const(ubyte)[])data;
564             }
565             else
566             {
567                 data_ = (cast(const(ubyte)*)data.ptr)[0 .. data.length * V.sizeof];
568             }
569         }
570         else
571         {
572             data_ = cast(const(ubyte)[])((cast(const(void)*)&data)[0 .. data.sizeof]);
573         }
574 
575         foreach (d; data_)
576         {
577             digest = fnv1_core(d, digest);
578         }
579 
580         return digest;
581     }
582 
583     public alias fnv1 opCall;
584 
585 
586     /**************************************************************************
587 
588         Calculates a FNV1/FNV1a digest from data and generates a hexdecimal
589         string representation of the digest. data are processed in
590         octet/byte-wise manner.
591 
592         Usage:
593 
594         ---
595 
596              import ocean.io.digest.Fnv;
597 
598              Fnv32.HexDigest digest32;
599              Fnv64.HexDigest digest64;
600 
601              auto data = "sociomantic";
602 
603              digest32 = Fnv32.fnv1(data, digest32);
604              digest64 = Fnv64.fnv1(data, digest32);
605 
606         ---
607 
608         Params:
609              data    = data to digest
610              hexdgst = string buffer
611              digest  = initial digest; defaults to the magic 32 bit or 64 bit
612                        initial value, according to DigestType
613 
614         Returns:
615              hexdecimal string representation of resulting digest
616 
617      **************************************************************************/
618 
619     public static char[] fnv1_hex ( U ) ( U data, char[] hexdgst, DigestType digest = INIT )
620     {
621         digest = fnv1(data, digest);
622 
623         foreach_reverse (ref h; hexdgst)
624         {
625             h = "0123456789abcdef"[digest & 0xF];
626 
627             digest >>= 4;
628         }
629 
630         return hexdgst;
631     }
632 
633 
634     /**************************************************************************
635 
636         FNV1/FNV1a core; calculates a digest of one octet d
637 
638         Params:
639              d      = data to digest
640              digest = initial digest
641 
642         Returns:
643              resulting digest
644 
645      **************************************************************************/
646 
647     public static DigestType fnv1_core ( ubyte d, DigestType digest )
648     {
649         static if (FNV1A)
650         {
651             return (digest ^ d) * PRIME;
652         }
653         else
654         {
655             return (digest * PRIME) ^ d;
656         }
657     }
658 
659 
660     /***************************************************************************
661 
662         Creates a combined hash of all the provided parameters.
663         The previous hashed value is used as the initial state for the next.
664 
665         Params:
666             Vals = Tuple of value types, inferred.
667             vals = the values to be used for hashing
668 
669         Returns:
670             returns the combined hash
671 
672     ***************************************************************************/
673 
674     public static hash_t combined ( Vals... ) ( Vals vals )
675     {
676         hash_t hash = INIT;
677 
678         foreach (val; vals)
679         {
680             hash = fnv1(val, hash);
681         }
682 
683         return hash;
684     }
685 }
686 
687 
688 /**************************************************************************
689 
690     unit test
691 
692 
693     Test data for FNV1/FNV1a hash algorithm
694 
695     Data taken from Landon Curt Noll's FNV test program source code:
696 
697         http://www.isthe.com/chongo/src/fnv/test_fnv.c
698 
699     found at his FNV web page:
700 
701         http://www.isthe.com/chongo/tech/comp/fnv/
702 
703 
704     The original code was released as public domain by chongo <Landon Curt
705     Noll>:
706     http://web.archive.org/web/20101105131957/http://www.isthe.com/chongo/src/fnv/test_fnv.c
707 
708     C to D port by David Eckardt, dunnhumby Germany GmbH, October 2009
709 
710 **************************************************************************/
711 
712 
713 version (unittest)
714 {
715     // Uncomment the next line to see UnitTest output
716     // version = UnitTestVerbose;
717 
718     private istring errmsg ( istring func, istring str, bool is_text )
719     {
720         auto errmsg = "unit test failed for " ~ func;
721 
722         if (is_text)
723         {
724             errmsg ~= ": \"" ~ str ~ "\"";
725         }
726 
727         return errmsg;
728     }
729 }
730 
731 unittest
732 {
733     struct TestData
734     {
735         /*
736          * 32-bit FNV1 digests of "string" below as integer, binary data string
737          * and hexadecimal text string
738          */
739         uint    fnv1_32;
740         ubyte[] fnv1_32_bin;
741         istring  fnv1_32_hex;
742 
743         /*
744          * 32-bit FNV1a digests of "string" below as integer, binary data string
745          * and hexadecimal text string
746          */
747         uint    fnv1a_32;
748         ubyte[] fnv1a_32_bin;
749         istring  fnv1a_32_hex;
750 
751         /*
752          * 64-bit FNV1 digests of "string" below as integer, binary data string
753          * and hexadecimal text string
754          */
755         ulong   fnv1_64;
756         ubyte[] fnv1_64_bin;
757         istring  fnv1_64_hex;
758 
759         /*
760          * 64-bit FNV1a digests of "string" below as integer, binary data string
761          * and hexadecimal text string
762          */
763         ulong   fnv1a_64;
764         ubyte[] fnv1a_64_bin;
765         istring  fnv1a_64_hex;
766 
767         /*
768          * is_text == true indicates that the content of "string" is safe to
769          * write to a text output (text file, console...).
770          */
771         bool   is_text;
772 
773         // string of which the digests above are computed from
774         istring str;
775     }
776 
777     static immutable TestData[] testdata =
778     [
779         {0xc5f1d7e9, [0xc5, 0xf1, 0xd7, 0xe9], "c5f1d7e9", 0x512b2851, [0x51, 0x2b, 0x28, 0x51], "512b2851", 0x43c94e2c8b277509, [0x43, 0xc9, 0x4e, 0x2c, 0x8b, 0x27, 0x75, 0x09], "43c94e2c8b277509", 0x33b96c3cd65b5f71, [0x33, 0xb9, 0x6c, 0x3c, 0xd6, 0x5b, 0x5f, 0x71], "33b96c3cd65b5f71",  true, "391581216093391581216093391581216093391581216093391581216093391581216093391581216093391581216093391581216093391581216093"},
780         {0x32c1f439, [0x32, 0xc1, 0xf4, 0x39], "32c1f439", 0x76823999, [0x76, 0x82, 0x39, 0x99], "76823999", 0x3cbfd4e4ea670359, [0x3c, 0xbf, 0xd4, 0xe4, 0xea, 0x67, 0x03, 0x59], "3cbfd4e4ea670359", 0xd845097780602bb9, [0xd8, 0x45, 0x09, 0x77, 0x80, 0x60, 0x2b, 0xb9], "d845097780602bb9",  true, "391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1"},
781         {0x7fd3eb7d, [0x7f, 0xd3, 0xeb, 0x7d], "7fd3eb7d", 0xc0586935, [0xc0, 0x58, 0x69, 0x35], "c0586935", 0xc05887810f4d019d, [0xc0, 0x58, 0x87, 0x81, 0x0f, 0x4d, 0x01, 0x9d], "c05887810f4d019d", 0x84d47645d02da3d5, [0x84, 0xd4, 0x76, 0x45, 0xd0, 0x2d, 0xa3, 0xd5], "84d47645d02da3d5", false, "\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81"},
782         {0x81597da5, [0x81, 0x59, 0x7d, 0xa5], "81597da5", 0xf3415c85, [0xf3, 0x41, 0x5c, 0x85], "f3415c85", 0x14468ff93ac22dc5, [0x14, 0x46, 0x8f, 0xf9, 0x3a, 0xc2, 0x2d, 0xc5], "14468ff93ac22dc5", 0x83544f33b58773a5, [0x83, 0x54, 0x4f, 0x33, 0xb5, 0x87, 0x73, 0xa5], "83544f33b58773a5", false, "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210"},
783         {0x05eb7a25, [0x05, 0xeb, 0x7a, 0x25], "05eb7a25", 0x0ae4ff65, [0x0a, 0xe4, 0xff, 0x65], "0ae4ff65", 0xebed699589d99c05, [0xeb, 0xed, 0x69, 0x95, 0x89, 0xd9, 0x9c, 0x05], "ebed699589d99c05", 0x9175cbb2160836c5, [0x91, 0x75, 0xcb, 0xb2, 0x16, 0x08, 0x36, 0xc5], "9175cbb2160836c5", false, "\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10"},
784         {0x9c0fa1b5, [0x9c, 0x0f, 0xa1, 0xb5], "9c0fa1b5", 0x58b79725, [0x58, 0xb7, 0x97, 0x25], "58b79725", 0x6d99f6df321ca5d5, [0x6d, 0x99, 0xf6, 0xdf, 0x32, 0x1c, 0xa5, 0xd5], "6d99f6df321ca5d5", 0xc71b3bc175e72bc5, [0xc7, 0x1b, 0x3b, 0xc1, 0x75, 0xe7, 0x2b, 0xc5], "c71b3bc175e72bc5",  true, "EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301"},
785         {0x53ccb1c5, [0x53, 0xcc, 0xb1, 0xc5], "53ccb1c5", 0xdea43aa5, [0xde, 0xa4, 0x3a, 0xa5], "dea43aa5", 0x0cd410d08c36d625, [0x0c, 0xd4, 0x10, 0xd0, 0x8c, 0x36, 0xd6, 0x25], "0cd410d08c36d625", 0x636806ac222ec985, [0x63, 0x68, 0x06, 0xac, 0x22, 0x2e, 0xc9, 0x85], "636806ac222ec985", false, "\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01"},
786         {0xfabece15, [0xfa, 0xbe, 0xce, 0x15], "fabece15", 0x2bb3be35, [0x2b, 0xb3, 0xbe, 0x35], "2bb3be35", 0xef1b2a2c86831d35, [0xef, 0x1b, 0x2a, 0x2c, 0x86, 0x83, 0x1d, 0x35], "ef1b2a2c86831d35", 0xb6ef0e6950f52ed5, [0xb6, 0xef, 0x0e, 0x69, 0x50, 0xf5, 0x2e, 0xd5], "b6ef0e6950f52ed5",  true, "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"},
787         {0x4ad745a5, [0x4a, 0xd7, 0x45, 0xa5], "4ad745a5", 0xea777a45, [0xea, 0x77, 0x7a, 0x45], "ea777a45", 0x3b349c4d69ee5f05, [0x3b, 0x34, 0x9c, 0x4d, 0x69, 0xee, 0x5f, 0x05], "3b349c4d69ee5f05", 0xead3d8a0f3dfdaa5, [0xea, 0xd3, 0xd8, 0xa0, 0xf3, 0xdf, 0xda, 0xa5], "ead3d8a0f3dfdaa5", false, "\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef"},
788         {0xe5bdc495, [0xe5, 0xbd, 0xc4, 0x95], "e5bdc495", 0x8f21c305, [0x8f, 0x21, 0xc3, 0x05], "8f21c305", 0x55248ce88f45f035, [0x55, 0x24, 0x8c, 0xe8, 0x8f, 0x45, 0xf0, 0x35], "55248ce88f45f035", 0x922908fe9a861ba5, [0x92, 0x29, 0x08, 0xfe, 0x9a, 0x86, 0x1b, 0xa5], "922908fe9a861ba5",  true, "1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE"},
789         {0x23b3c0a5, [0x23, 0xb3, 0xc0, 0xa5], "23b3c0a5", 0x5c9d0865, [0x5c, 0x9d, 0x08, 0x65], "5c9d0865", 0xaa69ca6a18a4c885, [0xaa, 0x69, 0xca, 0x6a, 0x18, 0xa4, 0xc8, 0x85], "aa69ca6a18a4c885", 0x6d4821de275fd5c5, [0x6d, 0x48, 0x21, 0xde, 0x27, 0x5f, 0xd5, 0xc5], "6d4821de275fd5c5", false, "\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe"},
790         {0xfa823dd5, [0xfa, 0x82, 0x3d, 0xd5], "fa823dd5", 0xfa823dd5, [0xfa, 0x82, 0x3d, 0xd5], "fa823dd5", 0x1fe3fce62bd816b5, [0x1f, 0xe3, 0xfc, 0xe6, 0x2b, 0xd8, 0x16, 0xb5], "1fe3fce62bd816b5", 0x1fe3fce62bd816b5, [0x1f, 0xe3, 0xfc, 0xe6, 0x2b, 0xd8, 0x16, 0xb5], "1fe3fce62bd816b5", false, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"},
791         {0x0c6c58b9, [0x0c, 0x6c, 0x58, 0xb9], "0c6c58b9", 0x21a27271, [0x21, 0xa2, 0x72, 0x71], "21a27271", 0x0289a488a8df69d9, [0x02, 0x89, 0xa4, 0x88, 0xa8, 0xdf, 0x69, 0xd9], "0289a488a8df69d9", 0xc23e9fccd6f70591, [0xc2, 0x3e, 0x9f, 0xcc, 0xd6, 0xf7, 0x05, 0x91], "c23e9fccd6f70591", false, "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07"},
792         {0xe2dbccd5, [0xe2, 0xdb, 0xcc, 0xd5], "e2dbccd5", 0x83c5c6d5, [0x83, 0xc5, 0xc6, 0xd5], "83c5c6d5", 0x15e96e1613df98b5, [0x15, 0xe9, 0x6e, 0x16, 0x13, 0xdf, 0x98, 0xb5], "15e96e1613df98b5", 0xc1af12bdfe16b5b5, [0xc1, 0xaf, 0x12, 0xbd, 0xfe, 0x16, 0xb5, 0xb5], "c1af12bdfe16b5b5",  true, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"},
793         {0xdb7f50f9, [0xdb, 0x7f, 0x50, 0xf9], "db7f50f9", 0x813b0881, [0x81, 0x3b, 0x08, 0x81], "813b0881", 0xe6be57375ad89b99, [0xe6, 0xbe, 0x57, 0x37, 0x5a, 0xd8, 0x9b, 0x99], "e6be57375ad89b99", 0x39e9f18f2f85e221, [0x39, 0xe9, 0xf1, 0x8f, 0x2f, 0x85, 0xe2, 0x21], "39e9f18f2f85e221", false, "\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f"}
794      ];
795 
796     scope Fnv1a32 fnv1a32 = new Fnv1a32;
797     scope Fnv1a64 fnv1a64 = new Fnv1a64;
798 
799     foreach (tdat; testdata)
800     {
801         /**********************************************************************
802 
803              core methods test
804 
805          **********************************************************************/
806 
807         test (Fnv1a32.fnv1(tdat.str) == tdat.fnv1a_32, errmsg("Fnv1a32.fnv1", tdat.str, tdat.is_text));
808         test (Fnv1a64.fnv1(tdat.str) == tdat.fnv1a_64, errmsg("Fnv1a64.fnv1", tdat.str, tdat.is_text));
809 
810         /**********************************************************************
811 
812             class methods test
813 
814          **********************************************************************/
815 
816         test (fnv1a32.update(tdat.str).hexDigest == tdat.fnv1a_32_hex, errmsg("Fnv1a32.hexDigest", tdat.str, tdat.is_text));
817         test (fnv1a64.update(tdat.str).hexDigest == tdat.fnv1a_64_hex, errmsg("Fnv1a64.hexDigest", tdat.str, tdat.is_text));
818     }
819 
820 
821     test ( StaticFnv1a32!("myString") == Fnv1a32("myString"[]), "CompileTime Fnv1a32 failed");
822     test ( StaticFnv1a32!("TEST") == Fnv1a32("TEST"[]), "CompileTime Fnv1a32 failed");
823 
824 
825     istring d1 = "ABC";
826     int d2 = 123;
827     ulong d3 = 12354;
828 
829     auto chash = Fnv1a.combined(d1, d2, d3);
830 
831     auto mhash = Fnv1a(d3, Fnv1a(d2, Fnv1a(d1)));
832 
833     test (chash == mhash, "Combined hash failed");
834 }