1*627f7eb2Smrg /**
2*627f7eb2Smrg Cyclic Redundancy Check (32-bit) implementation.
3*627f7eb2Smrg
4*627f7eb2Smrg $(SCRIPT inhibitQuickIndex = 1;)
5*627f7eb2Smrg
6*627f7eb2Smrg $(DIVC quickindex,
7*627f7eb2Smrg $(BOOKTABLE ,
8*627f7eb2Smrg $(TR $(TH Category) $(TH Functions)
9*627f7eb2Smrg )
10*627f7eb2Smrg $(TR $(TDNW Template API) $(TD $(MYREF CRC) $(MYREF CRC32) $(MYREF CRC64ECMA) $(MYREF CRC64ISO)
11*627f7eb2Smrg )
12*627f7eb2Smrg )
13*627f7eb2Smrg $(TR $(TDNW OOP API) $(TD $(MYREF CRC32Digest) $(MYREF CRC64ECMADigest) $(MYREF CRC64ISODigest))
14*627f7eb2Smrg )
15*627f7eb2Smrg $(TR $(TDNW Helpers) $(TD $(MYREF crcHexString) $(MYREF crc32Of) $(MYREF crc64ECMAOf) $(MYREF crc64ISOOf))
16*627f7eb2Smrg )
17*627f7eb2Smrg )
18*627f7eb2Smrg )
19*627f7eb2Smrg
20*627f7eb2Smrg *
21*627f7eb2Smrg * This module conforms to the APIs defined in $(D std.digest). To understand the
22*627f7eb2Smrg * differences between the template and the OOP API, see $(MREF std, digest).
23*627f7eb2Smrg *
24*627f7eb2Smrg * This module publicly imports $(MREF std, digest) and can be used as a stand-alone
25*627f7eb2Smrg * module.
26*627f7eb2Smrg *
27*627f7eb2Smrg * Note:
28*627f7eb2Smrg * CRCs are usually printed with the MSB first. When using
29*627f7eb2Smrg * $(REF toHexString, std,digest) the result will be in an unexpected
30*627f7eb2Smrg * order. Use $(REF toHexString, std,digest)'s optional order parameter
31*627f7eb2Smrg * to specify decreasing order for the correct result. The $(LREF crcHexString)
32*627f7eb2Smrg * alias can also be used for this purpose.
33*627f7eb2Smrg *
34*627f7eb2Smrg * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
35*627f7eb2Smrg *
36*627f7eb2Smrg * Authors: Pavel "EvilOne" Minayev, Alex Rønne Petersen, Johannes Pfau
37*627f7eb2Smrg *
38*627f7eb2Smrg * References:
39*627f7eb2Smrg * $(LINK2 http://en.wikipedia.org/wiki/Cyclic_redundancy_check, Wikipedia on CRC)
40*627f7eb2Smrg *
41*627f7eb2Smrg * Source: $(PHOBOSSRC std/digest/_crc.d)
42*627f7eb2Smrg *
43*627f7eb2Smrg * Standards:
44*627f7eb2Smrg * Implements the 'common' IEEE CRC32 variant
45*627f7eb2Smrg * (LSB-first order, Initial value uint.max, complement result)
46*627f7eb2Smrg *
47*627f7eb2Smrg * CTFE:
48*627f7eb2Smrg * Digests do not work in CTFE
49*627f7eb2Smrg */
50*627f7eb2Smrg /*
51*627f7eb2Smrg * Copyright (c) 2001 - 2002
52*627f7eb2Smrg * Pavel "EvilOne" Minayev
53*627f7eb2Smrg * Copyright (c) 2012
54*627f7eb2Smrg * Alex Rønne Petersen
55*627f7eb2Smrg * Distributed under the Boost Software License, Version 1.0.
56*627f7eb2Smrg * (See accompanying file LICENSE_1_0.txt or copy at
57*627f7eb2Smrg * http://www.boost.org/LICENSE_1_0.txt)
58*627f7eb2Smrg */
59*627f7eb2Smrg module std.digest.crc;
60*627f7eb2Smrg
61*627f7eb2Smrg public import std.digest;
62*627f7eb2Smrg
63*627f7eb2Smrg version (unittest)
64*627f7eb2Smrg import std.exception;
65*627f7eb2Smrg
66*627f7eb2Smrg
67*627f7eb2Smrg ///
68*627f7eb2Smrg @safe unittest
69*627f7eb2Smrg {
70*627f7eb2Smrg //Template API
71*627f7eb2Smrg import std.digest.crc;
72*627f7eb2Smrg
73*627f7eb2Smrg ubyte[4] hash = crc32Of("The quick brown fox jumps over the lazy dog");
74*627f7eb2Smrg assert(crcHexString(hash) == "414FA339");
75*627f7eb2Smrg
76*627f7eb2Smrg //Feeding data
77*627f7eb2Smrg ubyte[1024] data;
78*627f7eb2Smrg CRC32 crc;
79*627f7eb2Smrg crc.put(data[]);
80*627f7eb2Smrg crc.start(); //Start again
81*627f7eb2Smrg crc.put(data[]);
82*627f7eb2Smrg hash = crc.finish();
83*627f7eb2Smrg }
84*627f7eb2Smrg
85*627f7eb2Smrg ///
86*627f7eb2Smrg @safe unittest
87*627f7eb2Smrg {
88*627f7eb2Smrg //OOP API
89*627f7eb2Smrg import std.digest.crc;
90*627f7eb2Smrg
91*627f7eb2Smrg auto crc = new CRC32Digest();
92*627f7eb2Smrg ubyte[] hash = crc.digest("The quick brown fox jumps over the lazy dog");
93*627f7eb2Smrg assert(crcHexString(hash) == "414FA339"); //352441c2
94*627f7eb2Smrg
95*627f7eb2Smrg //Feeding data
96*627f7eb2Smrg ubyte[1024] data;
97*627f7eb2Smrg crc.put(data[]);
98*627f7eb2Smrg crc.reset(); //Start again
99*627f7eb2Smrg crc.put(data[]);
100*627f7eb2Smrg hash = crc.finish();
101*627f7eb2Smrg }
102*627f7eb2Smrg
genTables(T)103*627f7eb2Smrg private T[256][8] genTables(T)(T polynomial)
104*627f7eb2Smrg {
105*627f7eb2Smrg T[256][8] res = void;
106*627f7eb2Smrg
107*627f7eb2Smrg foreach (i; 0 .. 0x100)
108*627f7eb2Smrg {
109*627f7eb2Smrg T crc = i;
110*627f7eb2Smrg foreach (_; 0 .. 8)
111*627f7eb2Smrg crc = (crc >> 1) ^ (-int(crc & 1) & polynomial);
112*627f7eb2Smrg res[0][i] = crc;
113*627f7eb2Smrg }
114*627f7eb2Smrg
115*627f7eb2Smrg foreach (i; 0 .. 0x100)
116*627f7eb2Smrg {
117*627f7eb2Smrg res[1][i] = (res[0][i] >> 8) ^ res[0][res[0][i] & 0xFF];
118*627f7eb2Smrg res[2][i] = (res[1][i] >> 8) ^ res[0][res[1][i] & 0xFF];
119*627f7eb2Smrg res[3][i] = (res[2][i] >> 8) ^ res[0][res[2][i] & 0xFF];
120*627f7eb2Smrg res[4][i] = (res[3][i] >> 8) ^ res[0][res[3][i] & 0xFF];
121*627f7eb2Smrg res[5][i] = (res[4][i] >> 8) ^ res[0][res[4][i] & 0xFF];
122*627f7eb2Smrg res[6][i] = (res[5][i] >> 8) ^ res[0][res[5][i] & 0xFF];
123*627f7eb2Smrg res[7][i] = (res[6][i] >> 8) ^ res[0][res[6][i] & 0xFF];
124*627f7eb2Smrg }
125*627f7eb2Smrg return res;
126*627f7eb2Smrg }
127*627f7eb2Smrg
128*627f7eb2Smrg @system unittest
129*627f7eb2Smrg {
130*627f7eb2Smrg auto tables = genTables(0xEDB88320);
131*627f7eb2Smrg assert(tables[0][0] == 0x00000000 && tables[0][$ - 1] == 0x2d02ef8d && tables[7][$ - 1] == 0x264b06e6);
132*627f7eb2Smrg }
133*627f7eb2Smrg
134*627f7eb2Smrg /**
135*627f7eb2Smrg * Template API CRC32 implementation.
136*627f7eb2Smrg * See $(D std.digest) for differences between template and OOP API.
137*627f7eb2Smrg */
138*627f7eb2Smrg alias CRC32 = CRC!(32, 0xEDB88320);
139*627f7eb2Smrg
140*627f7eb2Smrg /**
141*627f7eb2Smrg * Template API CRC64-ECMA implementation.
142*627f7eb2Smrg * See $(D std.digest.digest) for differences between template and OOP API.
143*627f7eb2Smrg */
144*627f7eb2Smrg alias CRC64ECMA = CRC!(64, 0xC96C5795D7870F42);
145*627f7eb2Smrg
146*627f7eb2Smrg /**
147*627f7eb2Smrg * Template API CRC64-ISO implementation.
148*627f7eb2Smrg * See $(D std.digest.digest) for differences between template and OOP API.
149*627f7eb2Smrg */
150*627f7eb2Smrg alias CRC64ISO = CRC!(64, 0xD800000000000000);
151*627f7eb2Smrg
152*627f7eb2Smrg /**
153*627f7eb2Smrg * Generic Template API used for CRC32 and CRC64 implementations.
154*627f7eb2Smrg *
155*627f7eb2Smrg * The N parameter indicate the size of the hash in bits.
156*627f7eb2Smrg * The parameter P specify the polynomial to be used for reduction.
157*627f7eb2Smrg *
158*627f7eb2Smrg * You may want to use the CRC32, CRC65ECMA and CRC64ISO aliases
159*627f7eb2Smrg * for convenience.
160*627f7eb2Smrg *
161*627f7eb2Smrg * See $(D std.digest.digest) for differences between template and OOP API.
162*627f7eb2Smrg */
163*627f7eb2Smrg struct CRC(uint N, ulong P) if (N == 32 || N == 64)
164*627f7eb2Smrg {
165*627f7eb2Smrg private:
166*627f7eb2Smrg static if (N == 32)
167*627f7eb2Smrg {
168*627f7eb2Smrg alias T = uint;
169*627f7eb2Smrg }
170*627f7eb2Smrg else
171*627f7eb2Smrg {
172*627f7eb2Smrg alias T = ulong;
173*627f7eb2Smrg }
174*627f7eb2Smrg
175*627f7eb2Smrg static immutable T[256][8] tables = genTables!T(P);
176*627f7eb2Smrg
177*627f7eb2Smrg /**
178*627f7eb2Smrg * Type of the finished CRC hash.
179*627f7eb2Smrg * ubyte[4] if N is 32, ubyte[8] if N is 64.
180*627f7eb2Smrg */
181*627f7eb2Smrg alias R = ubyte[T.sizeof];
182*627f7eb2Smrg
183*627f7eb2Smrg // magic initialization constants
184*627f7eb2Smrg T _state = T.max;
185*627f7eb2Smrg
186*627f7eb2Smrg public:
187*627f7eb2Smrg /**
188*627f7eb2Smrg * Use this to feed the digest with data.
189*627f7eb2Smrg * Also implements the $(REF isOutputRange, std,range,primitives)
190*627f7eb2Smrg * interface for $(D ubyte) and $(D const(ubyte)[]).
191*627f7eb2Smrg */
put(scope const (ubyte)[]data...)192*627f7eb2Smrg void put(scope const(ubyte)[] data...) @trusted pure nothrow @nogc
193*627f7eb2Smrg {
194*627f7eb2Smrg T crc = _state;
195*627f7eb2Smrg // process eight bytes at once
196*627f7eb2Smrg while (data.length >= 8)
197*627f7eb2Smrg {
198*627f7eb2Smrg // Use byte-wise reads to support architectures without HW support
199*627f7eb2Smrg // for unaligned reads. This can be optimized by compilers to a single
200*627f7eb2Smrg // 32-bit read if unaligned reads are supported.
201*627f7eb2Smrg // DMD is not able to do this optimization though, so explicitly
202*627f7eb2Smrg // do unaligned reads for DMD's architectures.
203*627f7eb2Smrg version (X86)
204*627f7eb2Smrg enum hasLittleEndianUnalignedReads = true;
205*627f7eb2Smrg else version (X86_64)
206*627f7eb2Smrg enum hasLittleEndianUnalignedReads = true;
207*627f7eb2Smrg else
208*627f7eb2Smrg enum hasLittleEndianUnalignedReads = false; // leave decision to optimizer
209*627f7eb2Smrg static if (hasLittleEndianUnalignedReads)
210*627f7eb2Smrg {
211*627f7eb2Smrg uint one = (cast(uint*) data.ptr)[0];
212*627f7eb2Smrg uint two = (cast(uint*) data.ptr)[1];
213*627f7eb2Smrg }
214*627f7eb2Smrg else
215*627f7eb2Smrg {
216*627f7eb2Smrg uint one = (data.ptr[3] << 24 | data.ptr[2] << 16 | data.ptr[1] << 8 | data.ptr[0]);
217*627f7eb2Smrg uint two = (data.ptr[7] << 24 | data.ptr[6] << 16 | data.ptr[5] << 8 | data.ptr[4]);
218*627f7eb2Smrg }
219*627f7eb2Smrg
220*627f7eb2Smrg static if (N == 32)
221*627f7eb2Smrg {
222*627f7eb2Smrg one ^= crc;
223*627f7eb2Smrg }
224*627f7eb2Smrg else
225*627f7eb2Smrg {
226*627f7eb2Smrg one ^= (crc & 0xffffffff);
227*627f7eb2Smrg two ^= (crc >> 32);
228*627f7eb2Smrg }
229*627f7eb2Smrg
230*627f7eb2Smrg crc =
231*627f7eb2Smrg tables[0][two >> 24] ^
232*627f7eb2Smrg tables[1][(two >> 16) & 0xFF] ^
233*627f7eb2Smrg tables[2][(two >> 8) & 0xFF] ^
234*627f7eb2Smrg tables[3][two & 0xFF] ^
235*627f7eb2Smrg tables[4][one >> 24] ^
236*627f7eb2Smrg tables[5][(one >> 16) & 0xFF] ^
237*627f7eb2Smrg tables[6][(one >> 8) & 0xFF] ^
238*627f7eb2Smrg tables[7][one & 0xFF];
239*627f7eb2Smrg
240*627f7eb2Smrg data = data[8 .. $];
241*627f7eb2Smrg }
242*627f7eb2Smrg // remaining 1 to 7 bytes
243*627f7eb2Smrg foreach (d; data)
244*627f7eb2Smrg crc = (crc >> 8) ^ tables[0][(crc & 0xFF) ^ d];
245*627f7eb2Smrg _state = crc;
246*627f7eb2Smrg }
247*627f7eb2Smrg
248*627f7eb2Smrg /**
249*627f7eb2Smrg * Used to initialize the CRC32 digest.
250*627f7eb2Smrg *
251*627f7eb2Smrg * Note:
252*627f7eb2Smrg * For this CRC32 Digest implementation calling start after default construction
253*627f7eb2Smrg * is not necessary. Calling start is only necessary to reset the Digest.
254*627f7eb2Smrg *
255*627f7eb2Smrg * Generic code which deals with different Digest types should always call start though.
256*627f7eb2Smrg */
start()257*627f7eb2Smrg void start() @safe pure nothrow @nogc
258*627f7eb2Smrg {
259*627f7eb2Smrg this = CRC.init;
260*627f7eb2Smrg }
261*627f7eb2Smrg
262*627f7eb2Smrg /**
263*627f7eb2Smrg * Returns the finished CRC hash. This also calls $(LREF start) to
264*627f7eb2Smrg * reset the internal state.
265*627f7eb2Smrg */
finish()266*627f7eb2Smrg R finish() @safe pure nothrow @nogc
267*627f7eb2Smrg {
268*627f7eb2Smrg auto tmp = peek();
269*627f7eb2Smrg start();
270*627f7eb2Smrg return tmp;
271*627f7eb2Smrg }
272*627f7eb2Smrg
273*627f7eb2Smrg /**
274*627f7eb2Smrg * Works like $(D finish) but does not reset the internal state, so it's possible
275*627f7eb2Smrg * to continue putting data into this CRC after a call to peek.
276*627f7eb2Smrg */
peek()277*627f7eb2Smrg R peek() const @safe pure nothrow @nogc
278*627f7eb2Smrg {
279*627f7eb2Smrg import std.bitmanip : nativeToLittleEndian;
280*627f7eb2Smrg //Complement, LSB first / Little Endian, see http://rosettacode.org/wiki/CRC-32
281*627f7eb2Smrg return nativeToLittleEndian(~_state);
282*627f7eb2Smrg }
283*627f7eb2Smrg }
284*627f7eb2Smrg
285*627f7eb2Smrg ///
286*627f7eb2Smrg @safe unittest
287*627f7eb2Smrg {
288*627f7eb2Smrg //Simple example, hashing a string using crc32Of helper function
289*627f7eb2Smrg ubyte[4] hash32 = crc32Of("abc");
290*627f7eb2Smrg //Let's get a hash string
291*627f7eb2Smrg assert(crcHexString(hash32) == "352441C2");
292*627f7eb2Smrg // Repeat for CRC64
293*627f7eb2Smrg ubyte[8] hash64ecma = crc64ECMAOf("abc");
294*627f7eb2Smrg assert(crcHexString(hash64ecma) == "2CD8094A1A277627");
295*627f7eb2Smrg ubyte[8] hash64iso = crc64ISOOf("abc");
296*627f7eb2Smrg assert(crcHexString(hash64iso) == "3776C42000000000");
297*627f7eb2Smrg }
298*627f7eb2Smrg
299*627f7eb2Smrg ///
300*627f7eb2Smrg @safe unittest
301*627f7eb2Smrg {
302*627f7eb2Smrg ubyte[1024] data;
303*627f7eb2Smrg //Using the basic API
304*627f7eb2Smrg CRC32 hash32;
305*627f7eb2Smrg CRC64ECMA hash64ecma;
306*627f7eb2Smrg CRC64ISO hash64iso;
307*627f7eb2Smrg //Initialize data here...
308*627f7eb2Smrg hash32.put(data);
309*627f7eb2Smrg ubyte[4] result32 = hash32.finish();
310*627f7eb2Smrg hash64ecma.put(data);
311*627f7eb2Smrg ubyte[8] result64ecma = hash64ecma.finish();
312*627f7eb2Smrg hash64iso.put(data);
313*627f7eb2Smrg ubyte[8] result64iso = hash64iso.finish();
314*627f7eb2Smrg }
315*627f7eb2Smrg
316*627f7eb2Smrg ///
317*627f7eb2Smrg @safe unittest
318*627f7eb2Smrg {
319*627f7eb2Smrg //Let's use the template features:
320*627f7eb2Smrg //Note: When passing a CRC32 to a function, it must be passed by reference!
321*627f7eb2Smrg void doSomething(T)(ref T hash)
322*627f7eb2Smrg if (isDigest!T)
323*627f7eb2Smrg {
324*627f7eb2Smrg hash.put(cast(ubyte) 0);
325*627f7eb2Smrg }
326*627f7eb2Smrg CRC32 crc32;
327*627f7eb2Smrg crc32.start();
328*627f7eb2Smrg doSomething(crc32);
329*627f7eb2Smrg assert(crcHexString(crc32.finish()) == "D202EF8D");
330*627f7eb2Smrg // repeat for CRC64
331*627f7eb2Smrg CRC64ECMA crc64ecma;
332*627f7eb2Smrg crc64ecma.start();
333*627f7eb2Smrg doSomething(crc64ecma);
334*627f7eb2Smrg assert(crcHexString(crc64ecma.finish()) == "1FADA17364673F59");
335*627f7eb2Smrg CRC64ISO crc64iso;
336*627f7eb2Smrg crc64iso.start();
337*627f7eb2Smrg doSomething(crc64iso);
338*627f7eb2Smrg assert(crcHexString(crc64iso.finish()) == "6F90000000000000");
339*627f7eb2Smrg }
340*627f7eb2Smrg
341*627f7eb2Smrg @safe unittest
342*627f7eb2Smrg {
343*627f7eb2Smrg assert(isDigest!CRC32);
344*627f7eb2Smrg assert(isDigest!CRC64ECMA);
345*627f7eb2Smrg assert(isDigest!CRC64ISO);
346*627f7eb2Smrg }
347*627f7eb2Smrg
348*627f7eb2Smrg @system unittest
349*627f7eb2Smrg {
350*627f7eb2Smrg ubyte[4] digest;
351*627f7eb2Smrg
352*627f7eb2Smrg CRC32 crc;
353*627f7eb2Smrg crc.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz");
354*627f7eb2Smrg assert(crc.peek() == cast(ubyte[]) x"bd50274c");
355*627f7eb2Smrg crc.start();
356*627f7eb2Smrg crc.put(cast(ubyte[])"");
357*627f7eb2Smrg assert(crc.finish() == cast(ubyte[]) x"00000000");
358*627f7eb2Smrg
359*627f7eb2Smrg digest = crc32Of("");
360*627f7eb2Smrg assert(digest == cast(ubyte[]) x"00000000");
361*627f7eb2Smrg
362*627f7eb2Smrg //Test vector from http://rosettacode.org/wiki/CRC-32
363*627f7eb2Smrg assert(crcHexString(crc32Of("The quick brown fox jumps over the lazy dog")) == "414FA339");
364*627f7eb2Smrg
365*627f7eb2Smrg digest = crc32Of("a");
366*627f7eb2Smrg assert(digest == cast(ubyte[]) x"43beb7e8");
367*627f7eb2Smrg
368*627f7eb2Smrg digest = crc32Of("abc");
369*627f7eb2Smrg assert(digest == cast(ubyte[]) x"c2412435");
370*627f7eb2Smrg
371*627f7eb2Smrg digest = crc32Of("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
372*627f7eb2Smrg assert(digest == cast(ubyte[]) x"5f3f1a17");
373*627f7eb2Smrg
374*627f7eb2Smrg digest = crc32Of("message digest");
375*627f7eb2Smrg assert(digest == cast(ubyte[]) x"7f9d1520");
376*627f7eb2Smrg
377*627f7eb2Smrg digest = crc32Of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
378*627f7eb2Smrg assert(digest == cast(ubyte[]) x"d2e6c21f");
379*627f7eb2Smrg
380*627f7eb2Smrg digest = crc32Of("1234567890123456789012345678901234567890"~
381*627f7eb2Smrg "1234567890123456789012345678901234567890");
382*627f7eb2Smrg assert(digest == cast(ubyte[]) x"724aa97c");
383*627f7eb2Smrg
384*627f7eb2Smrg assert(crcHexString(cast(ubyte[4]) x"c3fcd3d7") == "D7D3FCC3");
385*627f7eb2Smrg }
386*627f7eb2Smrg
387*627f7eb2Smrg @system unittest
388*627f7eb2Smrg {
389*627f7eb2Smrg ubyte[8] digest;
390*627f7eb2Smrg
391*627f7eb2Smrg CRC64ECMA crc;
392*627f7eb2Smrg crc.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz");
393*627f7eb2Smrg assert(crc.peek() == cast(ubyte[]) x"2f121b7575789626");
394*627f7eb2Smrg crc.start();
395*627f7eb2Smrg crc.put(cast(ubyte[])"");
396*627f7eb2Smrg assert(crc.finish() == cast(ubyte[]) x"0000000000000000");
397*627f7eb2Smrg digest = crc64ECMAOf("");
398*627f7eb2Smrg assert(digest == cast(ubyte[]) x"0000000000000000");
399*627f7eb2Smrg
400*627f7eb2Smrg //Test vector from http://rosettacode.org/wiki/CRC-32
401*627f7eb2Smrg assert(crcHexString(crc64ECMAOf("The quick brown fox jumps over the lazy dog")) == "5B5EB8C2E54AA1C4");
402*627f7eb2Smrg
403*627f7eb2Smrg digest = crc64ECMAOf("a");
404*627f7eb2Smrg assert(digest == cast(ubyte[]) x"052b652e77840233");
405*627f7eb2Smrg
406*627f7eb2Smrg digest = crc64ECMAOf("abc");
407*627f7eb2Smrg assert(digest == cast(ubyte[]) x"2776271a4a09d82c");
408*627f7eb2Smrg
409*627f7eb2Smrg digest = crc64ECMAOf("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
410*627f7eb2Smrg assert(digest == cast(ubyte[]) x"4b7cdce3746c449f");
411*627f7eb2Smrg
412*627f7eb2Smrg digest = crc64ECMAOf("message digest");
413*627f7eb2Smrg assert(digest == cast(ubyte[]) x"6f9b8a3156c9bc5d");
414*627f7eb2Smrg
415*627f7eb2Smrg digest = crc64ECMAOf("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
416*627f7eb2Smrg assert(digest == cast(ubyte[]) x"2656b716e1bf0503");
417*627f7eb2Smrg
418*627f7eb2Smrg digest = crc64ECMAOf("1234567890123456789012345678901234567890"~
419*627f7eb2Smrg "1234567890123456789012345678901234567890");
420*627f7eb2Smrg assert(digest == cast(ubyte[]) x"bd3eb7765d0a22ae");
421*627f7eb2Smrg
422*627f7eb2Smrg assert(crcHexString(cast(ubyte[8]) x"c3fcd3d7efbeadde") == "DEADBEEFD7D3FCC3");
423*627f7eb2Smrg }
424*627f7eb2Smrg
425*627f7eb2Smrg @system unittest
426*627f7eb2Smrg {
427*627f7eb2Smrg ubyte[8] digest;
428*627f7eb2Smrg
429*627f7eb2Smrg CRC64ISO crc;
430*627f7eb2Smrg crc.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz");
431*627f7eb2Smrg assert(crc.peek() == cast(ubyte[]) x"f0494ab780989b42");
432*627f7eb2Smrg crc.start();
433*627f7eb2Smrg crc.put(cast(ubyte[])"");
434*627f7eb2Smrg assert(crc.finish() == cast(ubyte[]) x"0000000000000000");
435*627f7eb2Smrg digest = crc64ISOOf("");
436*627f7eb2Smrg assert(digest == cast(ubyte[]) x"0000000000000000");
437*627f7eb2Smrg
438*627f7eb2Smrg //Test vector from http://rosettacode.org/wiki/CRC-32
439*627f7eb2Smrg assert(crcHexString(crc64ISOOf("The quick brown fox jumps over the lazy dog")) == "4EF14E19F4C6E28E");
440*627f7eb2Smrg
441*627f7eb2Smrg digest = crc64ISOOf("a");
442*627f7eb2Smrg assert(digest == cast(ubyte[]) x"0000000000002034");
443*627f7eb2Smrg
444*627f7eb2Smrg digest = crc64ISOOf("abc");
445*627f7eb2Smrg assert(digest == cast(ubyte[]) x"0000000020c47637");
446*627f7eb2Smrg
447*627f7eb2Smrg digest = crc64ISOOf("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
448*627f7eb2Smrg assert(digest == cast(ubyte[]) x"5173f717971365e5");
449*627f7eb2Smrg
450*627f7eb2Smrg digest = crc64ISOOf("message digest");
451*627f7eb2Smrg assert(digest == cast(ubyte[]) x"a2c355bbc0b93f86");
452*627f7eb2Smrg
453*627f7eb2Smrg digest = crc64ISOOf("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
454*627f7eb2Smrg assert(digest == cast(ubyte[]) x"598B258292E40084");
455*627f7eb2Smrg
456*627f7eb2Smrg digest = crc64ISOOf("1234567890123456789012345678901234567890"~
457*627f7eb2Smrg "1234567890123456789012345678901234567890");
458*627f7eb2Smrg assert(digest == cast(ubyte[]) x"760cd2d3588bf809");
459*627f7eb2Smrg
460*627f7eb2Smrg assert(crcHexString(cast(ubyte[8]) x"c3fcd3d7efbeadde") == "DEADBEEFD7D3FCC3");
461*627f7eb2Smrg }
462*627f7eb2Smrg
463*627f7eb2Smrg /**
464*627f7eb2Smrg * This is a convenience alias for $(REF digest, std,digest) using the
465*627f7eb2Smrg * CRC32 implementation.
466*627f7eb2Smrg *
467*627f7eb2Smrg * Params:
468*627f7eb2Smrg * data = $(D InputRange) of $(D ElementType) implicitly convertible to
469*627f7eb2Smrg * $(D ubyte), $(D ubyte[]) or $(D ubyte[num]) or one or more arrays
470*627f7eb2Smrg * of any type.
471*627f7eb2Smrg *
472*627f7eb2Smrg * Returns:
473*627f7eb2Smrg * CRC32 of data
474*627f7eb2Smrg */
475*627f7eb2Smrg //simple alias doesn't work here, hope this gets inlined...
crc32Of(T...)476*627f7eb2Smrg ubyte[4] crc32Of(T...)(T data)
477*627f7eb2Smrg {
478*627f7eb2Smrg return digest!(CRC32, T)(data);
479*627f7eb2Smrg }
480*627f7eb2Smrg
481*627f7eb2Smrg ///
482*627f7eb2Smrg @system unittest
483*627f7eb2Smrg {
484*627f7eb2Smrg ubyte[] data = [4,5,7,25];
485*627f7eb2Smrg assert(data.crc32Of == [167, 180, 199, 131]);
486*627f7eb2Smrg
487*627f7eb2Smrg import std.utf : byChar;
488*627f7eb2Smrg assert("hello"d.byChar.crc32Of == [134, 166, 16, 54]);
489*627f7eb2Smrg
490*627f7eb2Smrg ubyte[4] hash = "abc".crc32Of();
491*627f7eb2Smrg assert(hash == digest!CRC32("ab", "c"));
492*627f7eb2Smrg
493*627f7eb2Smrg import std.range : iota;
494*627f7eb2Smrg enum ubyte S = 5, F = 66;
495*627f7eb2Smrg assert(iota(S, F).crc32Of == [59, 140, 234, 154]);
496*627f7eb2Smrg }
497*627f7eb2Smrg
498*627f7eb2Smrg /**
499*627f7eb2Smrg * This is a convenience alias for $(REF digest, std,digest) using the
500*627f7eb2Smrg * CRC64-ECMA implementation.
501*627f7eb2Smrg *
502*627f7eb2Smrg * Params:
503*627f7eb2Smrg * data = $(D InputRange) of $(D ElementType) implicitly convertible to
504*627f7eb2Smrg * $(D ubyte), $(D ubyte[]) or $(D ubyte[num]) or one or more arrays
505*627f7eb2Smrg * of any type.
506*627f7eb2Smrg *
507*627f7eb2Smrg * Returns:
508*627f7eb2Smrg * CRC64-ECMA of data
509*627f7eb2Smrg */
510*627f7eb2Smrg //simple alias doesn't work here, hope this gets inlined...
crc64ECMAOf(T...)511*627f7eb2Smrg ubyte[8] crc64ECMAOf(T...)(T data)
512*627f7eb2Smrg {
513*627f7eb2Smrg return digest!(CRC64ECMA, T)(data);
514*627f7eb2Smrg }
515*627f7eb2Smrg
516*627f7eb2Smrg ///
517*627f7eb2Smrg @system unittest
518*627f7eb2Smrg {
519*627f7eb2Smrg ubyte[] data = [4,5,7,25];
520*627f7eb2Smrg assert(data.crc64ECMAOf == [58, 142, 220, 214, 118, 98, 105, 69]);
521*627f7eb2Smrg
522*627f7eb2Smrg import std.utf : byChar;
523*627f7eb2Smrg assert("hello"d.byChar.crc64ECMAOf == [177, 55, 185, 219, 229, 218, 30, 155]);
524*627f7eb2Smrg
525*627f7eb2Smrg ubyte[8] hash = "abc".crc64ECMAOf();
526*627f7eb2Smrg assert("abc".crc64ECMAOf == [39, 118, 39, 26, 74, 9, 216, 44]);
527*627f7eb2Smrg assert(hash == digest!CRC64ECMA("ab", "c"));
528*627f7eb2Smrg
529*627f7eb2Smrg import std.range : iota;
530*627f7eb2Smrg enum ubyte S = 5, F = 66;
531*627f7eb2Smrg assert(iota(S, F).crc64ECMAOf == [6, 184, 91, 238, 46, 213, 127, 188]);
532*627f7eb2Smrg }
533*627f7eb2Smrg
534*627f7eb2Smrg /**
535*627f7eb2Smrg * This is a convenience alias for $(REF digest, std,digest,digest) using the
536*627f7eb2Smrg * CRC64-ISO implementation.
537*627f7eb2Smrg *
538*627f7eb2Smrg * Params:
539*627f7eb2Smrg * data = $(D InputRange) of $(D ElementType) implicitly convertible to
540*627f7eb2Smrg * $(D ubyte), $(D ubyte[]) or $(D ubyte[num]) or one or more arrays
541*627f7eb2Smrg * of any type.
542*627f7eb2Smrg *
543*627f7eb2Smrg * Returns:
544*627f7eb2Smrg * CRC64-ISO of data
545*627f7eb2Smrg */
546*627f7eb2Smrg //simple alias doesn't work here, hope this gets inlined...
crc64ISOOf(T...)547*627f7eb2Smrg ubyte[8] crc64ISOOf(T...)(T data)
548*627f7eb2Smrg {
549*627f7eb2Smrg return digest!(CRC64ISO, T)(data);
550*627f7eb2Smrg }
551*627f7eb2Smrg
552*627f7eb2Smrg ///
553*627f7eb2Smrg @system unittest
554*627f7eb2Smrg {
555*627f7eb2Smrg ubyte[] data = [4,5,7,25];
556*627f7eb2Smrg assert(data.crc64ISOOf == [0, 0, 0, 80, 137, 232, 203, 120]);
557*627f7eb2Smrg
558*627f7eb2Smrg import std.utf : byChar;
559*627f7eb2Smrg assert("hello"d.byChar.crc64ISOOf == [0, 0, 16, 216, 226, 238, 62, 60]);
560*627f7eb2Smrg
561*627f7eb2Smrg ubyte[8] hash = "abc".crc64ISOOf();
562*627f7eb2Smrg assert("abc".crc64ISOOf == [0, 0, 0, 0, 32, 196, 118, 55]);
563*627f7eb2Smrg assert(hash == digest!CRC64ISO("ab", "c"));
564*627f7eb2Smrg
565*627f7eb2Smrg import std.range : iota;
566*627f7eb2Smrg enum ubyte S = 5, F = 66;
567*627f7eb2Smrg
568*627f7eb2Smrg assert(iota(S, F).crc64ISOOf == [21, 185, 116, 95, 219, 11, 54, 7]);
569*627f7eb2Smrg }
570*627f7eb2Smrg
571*627f7eb2Smrg /**
572*627f7eb2Smrg * producing the usual CRC32 string output.
573*627f7eb2Smrg */
574*627f7eb2Smrg public alias crcHexString = toHexString!(Order.decreasing);
575*627f7eb2Smrg ///ditto
576*627f7eb2Smrg public alias crcHexString = toHexString!(Order.decreasing, 16);
577*627f7eb2Smrg
578*627f7eb2Smrg /**
579*627f7eb2Smrg * OOP API CRC32 implementation.
580*627f7eb2Smrg * See $(D std.digest) for differences between template and OOP API.
581*627f7eb2Smrg *
582*627f7eb2Smrg * This is an alias for $(D $(REF WrapperDigest, std,digest)!CRC32), see
583*627f7eb2Smrg * there for more information.
584*627f7eb2Smrg */
585*627f7eb2Smrg alias CRC32Digest = WrapperDigest!CRC32;
586*627f7eb2Smrg
587*627f7eb2Smrg /**
588*627f7eb2Smrg * OOP API CRC64-ECMA implementation.
589*627f7eb2Smrg * See $(D std.digest.digest) for differences between template and OOP API.
590*627f7eb2Smrg *
591*627f7eb2Smrg * This is an alias for $(D $(REF WrapperDigest, std,digest,digest)!CRC64ECMA),
592*627f7eb2Smrg * see there for more information.
593*627f7eb2Smrg */
594*627f7eb2Smrg alias CRC64ECMADigest = WrapperDigest!CRC64ECMA;
595*627f7eb2Smrg
596*627f7eb2Smrg /**
597*627f7eb2Smrg * OOP API CRC64-ISO implementation.
598*627f7eb2Smrg * See $(D std.digest.digest) for differences between template and OOP API.
599*627f7eb2Smrg *
600*627f7eb2Smrg * This is an alias for $(D $(REF WrapperDigest, std,digest,digest)!CRC64ISO),
601*627f7eb2Smrg * see there for more information.
602*627f7eb2Smrg */
603*627f7eb2Smrg alias CRC64ISODigest = WrapperDigest!CRC64ISO;
604*627f7eb2Smrg
605*627f7eb2Smrg ///
606*627f7eb2Smrg @safe unittest
607*627f7eb2Smrg {
608*627f7eb2Smrg //Simple example, hashing a string using Digest.digest helper function
609*627f7eb2Smrg auto crc = new CRC32Digest();
610*627f7eb2Smrg ubyte[] hash = crc.digest("abc");
611*627f7eb2Smrg //Let's get a hash string
612*627f7eb2Smrg assert(crcHexString(hash) == "352441C2");
613*627f7eb2Smrg }
614*627f7eb2Smrg
615*627f7eb2Smrg ///
616*627f7eb2Smrg @system unittest
617*627f7eb2Smrg {
618*627f7eb2Smrg //Let's use the OOP features:
test(Digest dig)619*627f7eb2Smrg void test(Digest dig)
620*627f7eb2Smrg {
621*627f7eb2Smrg dig.put(cast(ubyte) 0);
622*627f7eb2Smrg }
623*627f7eb2Smrg auto crc = new CRC32Digest();
624*627f7eb2Smrg test(crc);
625*627f7eb2Smrg
626*627f7eb2Smrg //Let's use a custom buffer:
627*627f7eb2Smrg ubyte[4] buf;
628*627f7eb2Smrg ubyte[] result = crc.finish(buf[]);
629*627f7eb2Smrg assert(crcHexString(result) == "D202EF8D");
630*627f7eb2Smrg }
631*627f7eb2Smrg
632*627f7eb2Smrg ///
633*627f7eb2Smrg @safe unittest
634*627f7eb2Smrg {
635*627f7eb2Smrg //Simple example
636*627f7eb2Smrg auto hash = new CRC32Digest();
637*627f7eb2Smrg hash.put(cast(ubyte) 0);
638*627f7eb2Smrg ubyte[] result = hash.finish();
639*627f7eb2Smrg }
640*627f7eb2Smrg
641*627f7eb2Smrg ///
642*627f7eb2Smrg @system unittest
643*627f7eb2Smrg {
644*627f7eb2Smrg //using a supplied buffer
645*627f7eb2Smrg ubyte[4] buf;
646*627f7eb2Smrg auto hash = new CRC32Digest();
647*627f7eb2Smrg hash.put(cast(ubyte) 0);
648*627f7eb2Smrg ubyte[] result = hash.finish(buf[]);
649*627f7eb2Smrg //The result is now in result (and in buf. If you pass a buffer which is bigger than
650*627f7eb2Smrg //necessary, result will have the correct length, but buf will still have it's original
651*627f7eb2Smrg //length)
652*627f7eb2Smrg }
653*627f7eb2Smrg
654*627f7eb2Smrg @system unittest
655*627f7eb2Smrg {
656*627f7eb2Smrg import std.range;
657*627f7eb2Smrg
658*627f7eb2Smrg auto crc = new CRC32Digest();
659*627f7eb2Smrg
660*627f7eb2Smrg crc.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz");
661*627f7eb2Smrg assert(crc.peek() == cast(ubyte[]) x"bd50274c");
662*627f7eb2Smrg crc.reset();
663*627f7eb2Smrg crc.put(cast(ubyte[])"");
664*627f7eb2Smrg assert(crc.finish() == cast(ubyte[]) x"00000000");
665*627f7eb2Smrg
666*627f7eb2Smrg crc.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz");
667*627f7eb2Smrg ubyte[20] result;
668*627f7eb2Smrg auto result2 = crc.finish(result[]);
669*627f7eb2Smrg assert(result[0 .. 4] == result2 && result2 == cast(ubyte[]) x"bd50274c");
670*627f7eb2Smrg
671*627f7eb2Smrg debug
672*627f7eb2Smrg assertThrown!Error(crc.finish(result[0 .. 3]));
673*627f7eb2Smrg
674*627f7eb2Smrg assert(crc.length == 4);
675*627f7eb2Smrg
676*627f7eb2Smrg assert(crc.digest("") == cast(ubyte[]) x"00000000");
677*627f7eb2Smrg
678*627f7eb2Smrg assert(crc.digest("a") == cast(ubyte[]) x"43beb7e8");
679*627f7eb2Smrg
680*627f7eb2Smrg assert(crc.digest("abc") == cast(ubyte[]) x"c2412435");
681*627f7eb2Smrg
682*627f7eb2Smrg assert(crc.digest("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")
683*627f7eb2Smrg == cast(ubyte[]) x"5f3f1a17");
684*627f7eb2Smrg
685*627f7eb2Smrg assert(crc.digest("message digest") == cast(ubyte[]) x"7f9d1520");
686*627f7eb2Smrg
687*627f7eb2Smrg assert(crc.digest("abcdefghijklmnopqrstuvwxyz")
688*627f7eb2Smrg == cast(ubyte[]) x"bd50274c");
689*627f7eb2Smrg
690*627f7eb2Smrg assert(crc.digest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
691*627f7eb2Smrg == cast(ubyte[]) x"d2e6c21f");
692*627f7eb2Smrg
693*627f7eb2Smrg assert(crc.digest("1234567890123456789012345678901234567890",
694*627f7eb2Smrg "1234567890123456789012345678901234567890")
695*627f7eb2Smrg == cast(ubyte[]) x"724aa97c");
696*627f7eb2Smrg
697*627f7eb2Smrg ubyte[] onemilliona = new ubyte[1000000];
698*627f7eb2Smrg onemilliona[] = 'a';
699*627f7eb2Smrg auto digest = crc32Of(onemilliona);
700*627f7eb2Smrg assert(digest == cast(ubyte[]) x"BCBF25DC");
701*627f7eb2Smrg
702*627f7eb2Smrg auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000);
703*627f7eb2Smrg digest = crc32Of(oneMillionRange);
704*627f7eb2Smrg assert(digest == cast(ubyte[]) x"BCBF25DC");
705*627f7eb2Smrg }
706