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 }