1 module blake3;
2 
3 version (Have_dynamic) {
4 	import blake3.binding;
5 	import dynamic;
6 
7 	__gshared mixin dynamicBinding!(blake3.binding) libblake3;
8 
9 	shared static this() {
10 		version (Windows)
11 			libblake3.loadBinding("libblake3");
12 		else
13 			libblake3.loadBinding("libblake3.so");
14 	}
15 } else
16 	import blake3.binding;
17 
18 @safe:
19 
20 alias Hasher = blake3_hasher;
21 
22 /// The hash value of empty input.
23 enum ubyte[32] emptyHash = cast(const(ubyte)[])x"af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262";
24 
25 /// A BLAKE3 hasher.
26 auto BLAKE3() @trusted {
27 	Hasher hasher = void;
28 	blake3_hasher_init(&hasher);
29 	return hasher;
30 }
31 
32 /// A BLAKE3 hasher with a key.
33 auto BLAKE3(in ubyte[BLAKE3_KEY_LEN] key) @trusted {
34 	Hasher hasher = void;
35 	blake3_hasher_init_keyed(&hasher, key);
36 	return hasher;
37 }
38 
39 /// A BLAKE3 hasher with a derived key.
40 auto BLAKE3(const char* context) @trusted {
41 	Hasher hasher = void;
42 	blake3_hasher_init_derive_key(&hasher, context);
43 	return hasher;
44 }
45 
46 /// A BLAKE3 hasher with a raw derived key.
47 auto BLAKE3(const(void)* context, size_t contextLen) @trusted {
48 	Hasher hasher = void;
49 	blake3_hasher_init_derive_key_raw(&hasher, context, contextLen);
50 	return hasher;
51 }
52 
53 /// Update the hasher with data.
54 void put(ref Hasher hasher, in void[] data) @trusted pure nothrow @nogc {
55 	blake3_hasher_update(&hasher, data.ptr, data.length);
56 }
57 
58 /// Finalize the hasher and return the hash value.
59 ubyte[L] finish(size_t L = BLAKE3_OUT_LEN)(const ref Hasher hasher) @trusted
60 if (L > 0 && L < 4096) {
61 	ubyte[L] output = void;
62 	blake3_hasher_finalize(&hasher, output.ptr, L);
63 	return output;
64 }
65 
66 /// ditto
67 ubyte[L] finish(size_t L = BLAKE3_OUT_LEN)(const ref Hasher hasher, ulong seek) @trusted
68 if (L > 0 && L < 4096) {
69 	ubyte[L] output = void;
70 	blake3_hasher_finalize_seek(&hasher, seek, output.ptr, L);
71 	return output;
72 }
73 
74 /// ditto
75 void finish(const ref Hasher hasher, ubyte[] output) @trusted {
76 	blake3_hasher_finalize(&hasher, output.ptr, output.length);
77 }
78 
79 /// ditto
80 void finish(const ref Hasher hasher, ubyte[] output, ulong seek) @trusted {
81 	blake3_hasher_finalize_seek(&hasher, seek, output.ptr, output.length);
82 }
83 
84 /// Reset the hasher to its initial state.
85 void reset(ref Hasher hasher) @trusted pure nothrow @nogc {
86 	blake3_hasher_reset(&hasher);
87 }
88 
89 /// Compute the BLAKE3 hash value of data.
90 ubyte[L] blake3Of(size_t L = BLAKE3_OUT_LEN)(in void[] data)
91 if (L > 0 && L < 4096) {
92 	auto hasher = BLAKE3();
93 	hasher.put(data);
94 	return hasher.finish!L();
95 }
96 
97 ///
98 unittest {
99 	assert(blake3Of([]) == emptyHash);
100 	assert(blake3Of("Hello world!") == x"793c10bc0b28c378330d39edace7260af9da81d603b8ffede2706a21eda893f4");
101 }
102 
103 ubyte[L] blake3Of(size_t L = 32)(in void[] data, in ubyte[32] key) {
104 	auto hasher = BLAKE3(key);
105 	hasher.put(data);
106 	return hasher.finish!L();
107 }