1 /// Implementation of Berus digester. 2 module tern.digest.berus; 3 4 import tern.serialization; 5 import tern.digest; 6 import std.conv; 7 8 /** 9 * Implementation of Berus digester. 10 * 11 * Berus is a modified Argon2 designed for lightweight and low-resource 12 * environments. It operates by dividing the input data into blocks, applying a series 13 * of operations, including XOR and addition, and then compressing the result. 14 * 15 * Example: 16 * ```d 17 * import tern.digest.berus; 18 * 19 * ubyte[] data = [1, 2, 3, 4, 5]; 20 * ubyte[] salt = [6, 7, 8, 9, 10]; 21 * auto hashValue = Berus.hash(data, salt); 22 * ``` 23 */ 24 public static @digester class Berus 25 { 26 private: 27 static: 28 pure: 29 enum BLOCK_SIZE = 32; 30 enum OPS_LIMIT = 14; 31 32 public: 33 /** 34 * Computes the Berus digest of the given data. 35 * 36 * Params: 37 * data - The data to be hashed. 38 * salt - The salt to be used in the hashing process. 39 * 40 * Returns: 41 * The hashed result as an array of ubytes. 42 */ 43 ubyte[] hash(ubyte[] data, ubyte[] salt) 44 { 45 ulong[BLOCK_SIZE] block; 46 47 foreach (i, ref b; block) 48 b += data[i % data.length]; 49 50 foreach (i, b; data) 51 block[i % BLOCK_SIZE] ^= b; 52 53 foreach (i, b; salt) 54 block[(i + BLOCK_SIZE / 2) % BLOCK_SIZE] ^= b; 55 56 void compress() 57 { 58 ulong F(ulong x, ulong y) 59 { 60 return (x + y) * (x ^ y); 61 } 62 63 foreach (i; 0..BLOCK_SIZE / 4) 64 { 65 block[i * 4] = F(block[i * 4], block[i * 4 + 1]); 66 block[i * 4 + 1] = F(block[i * 4 + 1], block[i * 4 + 2]); 67 block[i * 4 + 2] = F(block[i * 4 + 2], block[i * 4 + 3]); 68 block[i * 4 + 3] = F(block[i * 4 + 3], block[i * 4]); 69 } 70 71 foreach (i; 0..BLOCK_SIZE) 72 block[i] ^= block[(i + 1) % BLOCK_SIZE]; 73 74 foreach_reverse (i; 1..BLOCK_SIZE) 75 block[i] += block[i - 1]; 76 } 77 78 for (uint i = 0; i < OPS_LIMIT; i++) 79 compress(); 80 81 return block[0..8].serialize!true(); 82 } 83 }