1 module dcrypt.pqc.sphincs.common;
2 
3 /// Functions used in different SPHINCS components.
4 
5 import std.traits: ReturnType;
6 
7 import dcrypt.digests.blake;
8 import dcrypt.bitmanip;
9 
10 package:
11 
12 package template is_hash_n_n(alias func, H = ReturnType!func)
13 {
14 	enum bool is_hash_n_n =
15 		is(typeof(
16 				{
17 					H h1;
18 					h1 = func(h1);
19 				}));
20 }
21 
22 
23 package template is_hash_2n_n(alias func, H = ReturnType!func)
24 {
25 	enum bool is_hash_2n_n =
26 		is(typeof(
27 				{
28 					H h1, h2;
29 					h1 = func(h1, h2);
30 				}));
31 }
32 
33 package template is_prg(alias prg, uint seed_bytes)
34 {
35 	enum bool is_prg =
36 		is(typeof(
37 				{
38 					ubyte[] buf;
39 					ubyte[seed_bytes] seed;
40 					prg(buf, seed);
41 				}));
42 }
43 
44 /// Create the parent node of two sibling nodes in a binary hash tree.
45 /// Equals hash_2n_n_mask in ref.
46 /// Params:
47 /// left	=	Hash of left node.
48 /// right	=	Hash of right node.
49 /// bitmask	=	A bitmask for both nodes.
50 @safe @nogc pure nothrow
51 H hash_2n_n_mask(alias hash_2n_n, H, M)(in ref H left, in ref H right, in ref M bitmask)
52 	if(2*H.length == M.length && is_hash_2n_n!(hash_2n_n, H))
53 {
54 	return hash_2n_n_mask!(hash_2n_n, H)(left, right, bitmask[0..$/2], bitmask[$/2..$]);
55 }
56 
57 /// Create the parent node of two sibling nodes in a binary hash tree.
58 /// Equals hash_2n_n_mask in ref.
59 /// 
60 /// Params:
61 /// left	=	Hash of left node.
62 /// right	=	Hash of right node.
63 /// bitmask_left	=	Bitmask for left hash.
64 /// bitmask_right	=	Bitmask for left right.
65 @safe @nogc pure nothrow 
66 H hash_2n_n_mask(alias hash_2n_n, H)(in ref H left, in ref H right, in ref H bitmask_left, in ref H bitmask_right)
67 	if(is_hash_2n_n!(hash_2n_n, H))
68 {
69 	H m1 = left;
70 	H m2 = right;
71 	m1[] ^= bitmask_left[];
72 	m2[] ^= bitmask_right[];
73 	return hash_2n_n(m1, m2);
74 }
75 
76 /// Wrapper for hash!Blake256.
77 template varlen_hash(T...) {
78 	@safe @nogc
79 	auto varlen_hash(T...)(in T data) nothrow {
80 		return hash!Blake256(data);
81 	}
82 }
83 
84 
85 // Sanity test for varlen_hash.
86 private unittest {
87 	ubyte[] a = [1,2,3];
88 	ubyte[] b = [4,5,6];
89 
90 	assert(varlen_hash(a) != varlen_hash(b));
91 	assert(varlen_hash(a,b) == varlen_hash(a~b));
92 }
93 
94 /// Calclulate the number of digits of x in base 'base' representation.
95 @nogc @safe pure nothrow
96 package uint num_digits(ulong x, uint base) {
97 	uint log = 0;
98 	while(x > 0) {
99 		++log;
100 		x /= base;
101 	}
102 	return log;
103 }
104 
105 private unittest {
106 	assert(num_digits(255, 2) == 8);
107 	assert(num_digits(256, 2) == 9);
108 
109 	assert(num_digits(1, 10) == 1);
110 	assert(num_digits(9, 10) == 1);
111 	assert(num_digits(10, 10) == 2);
112 	assert(num_digits(99, 10) == 2);
113 	assert(num_digits(100, 10) == 3);
114 }