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 }