1 module dcrypt.util;
2 
3 import core.vararg;
4 import std.traits;
5 import std.algorithm;
6 
7 /// TODO: neat variadic implementation of `wipe()`
8 
9 /// Clears data in memory.
10 @safe @nogc nothrow
11 void wipe(T)(ref T t) {
12 	static if(isArray!T) {
13 		t[] = 0;
14 		assert(all!"a == 0"(t[]), "Failed to wipe ubyte[].");
15 	} else static if ( is(typeof( {T a = T.init;} ))) {
16 		t = T.init;
17 	} else {
18 		static assert(false, "Type not supported for wiping: " ~ T.stringof);
19 	}
20 }
21 
22 
23 @safe @nogc nothrow
24 void wipe(T...)(ref T ts) {
25 	foreach(ref t; ts) {
26 		wipe(t);
27 	}
28 }
29 
30 // test static arrays
31 unittest {
32 	ubyte[4] buf1 = [1,2,3,4];
33 	uint[4] buf2 = [1,2,3,4];
34 	size_t[4] buf3 = [1,2,3,4];
35 
36 	wipe(buf1);
37 	wipe(buf2);
38 	wipe(buf3);
39 
40 	assert(all!"a == 0"(buf1[]), "Failed to wipe ubyte[].");
41 	assert(all!"a == 0"(buf2[]), "Failed to wipe ubyte[].");
42 	assert(all!"a == 0"(buf3[]), "Failed to wipe ubyte[].");
43 }
44 
45 // test dynamic arrays
46 unittest {
47 	ubyte[] buf1 = [1,2,3,4];
48 	uint[] buf2 = [1,2,3,4];
49 	size_t[] buf3 = [1,2,3,4];
50 
51 	wipe(buf1, buf2, buf3);
52 	
53 	assert(all!"a == 0"(buf1), "Failed to wipe ubyte[].");
54 	assert(all!"a == 0"(buf2), "Failed to wipe ubyte[].");
55 	assert(all!"a == 0"(buf3), "Failed to wipe ubyte[].");
56 }
57 
58 unittest {
59 	int a = 42;
60 	int b = 84;
61 	ubyte c = 1;
62 
63 	wipe(a, b, c);
64 
65 	assert(a == 0 && b == 0 && c == 0, "Wiping integer failed!");
66 }
67 
68 /// Compares a and b in constant time.
69 /// 
70 /// Returns: 0 if a == b, some other value if a != b.
71 bool crypto_equals(T)(in T[] a, in T[] b) pure nothrow @safe @nogc
72 in {
73 	assert(a.length == b.length, "Unequal length.");
74 } body  {
75 	T result = 0;
76 	size_t i = 0;
77 
78 	while(i < a.length) {
79 		result |= a[i] ^ b[i];
80 		++i;
81 	}
82 
83 	if(i != a.length) {
84 		// Just to be sure that the compiler optimization does not destroy const time.
85 		assert(false);
86 	}
87 
88 	return result == 0;
89 }
90 
91 // test crypto_equals
92 unittest {
93 	ubyte[32] f = 0;
94 	immutable ubyte[32] zero = 0;
95 	assert(crypto_equals(f[], zero[]));
96 	f[8] = 1;
97 	assert(!crypto_equals(f[], zero[]));
98 }