1 /* COPYING ******************************************************************
2 For copyright and licensing terms, see the file named COPYING.
3 // **************************************************************************
4 */
5 
6 #include <stdint.h>
7 
8 class CubeHash {
9 public:
10 	unsigned char hashval[512/8];
11 
12 	// tunable parameters as per Dan Bernstein's 2009-09 NIST submission
CubeHash(unsigned int i,unsigned int r,unsigned int b,unsigned int f,unsigned int h)13 	CubeHash(unsigned int i, unsigned int r, unsigned int b, unsigned int f, unsigned int h) :
14 		initial_rounds(i),
15 		block_rounds(r),
16 		final_rounds(f),
17 		bytes_per_block(b),
18 		hashbytelen((h + 7) / 8),
19 		byte_pos(0)
20 	{
21 		Init();
22 	}
23 
Update(const unsigned char * data,std::size_t databytelen)24 	void Update(const unsigned char *data, std::size_t databytelen)
25 	{
26 		while (databytelen > 0) {
27 			const uint32_t u(uint32_t(*data) << (8U * (byte_pos % 4U)));
28 			x[byte_pos / 4U] ^= u;
29 			++data;
30 			--databytelen;
31 			++byte_pos;
32 			if (byte_pos == bytes_per_block) {
33 				transform(block_rounds);
34 				byte_pos = 0U;
35 			}
36 		}
37 	}
38 
Final()39 	void Final()
40 	{
41 		const uint32_t u(uint32_t(128) << (8U * (byte_pos % 4U)));
42 		x[byte_pos / 4U] ^= u;
43 		transform(block_rounds);
44 		x[31U] ^= 1U;
45 		transform(final_rounds);
46 		for (unsigned i = 0;i < hashbytelen;++i)
47 			hashval[i] = static_cast<unsigned char>(x[i / 4U] >> (8U * (i % 4U)));
48 	}
49 
50 protected:
51 	const unsigned int initial_rounds;
52 	const unsigned int block_rounds;
53 	const unsigned int final_rounds;
54 	const unsigned int bytes_per_block;
55 	const unsigned int hashbytelen;
56 	unsigned int byte_pos; ///< number of bytes read into x from current block
57 	uint32_t x[32];
58 
ROTATE(uint32_t a,uint32_t b)59 	uint32_t ROTATE(uint32_t a, uint32_t b) { return (a << b) | (a >> (32U - b)); }
60 
transform(unsigned int rounds)61 	void transform(unsigned int rounds)
62 	{
63 		enum { HALF_LENGTH = (sizeof x/sizeof *x) / 2 };
64 		uint32_t y[HALF_LENGTH];
65 
66 		for (unsigned r = rounds;r > 0;--r) {
67 			for (unsigned i = 0;i < HALF_LENGTH;++i) x[i + HALF_LENGTH] += x[i];
68 			for (unsigned i = 0;i < HALF_LENGTH;++i) y[i ^ 8] = x[i];
69 			for (unsigned i = 0;i < HALF_LENGTH;++i) x[i] = ROTATE(y[i],7);
70 			for (unsigned i = 0;i < HALF_LENGTH;++i) x[i] ^= x[i + HALF_LENGTH];
71 			for (unsigned i = 0;i < HALF_LENGTH;++i) y[i ^ 2] = x[i + HALF_LENGTH];
72 			for (unsigned i = 0;i < HALF_LENGTH;++i) x[i + HALF_LENGTH] = y[i];
73 			for (unsigned i = 0;i < HALF_LENGTH;++i) x[i + HALF_LENGTH] += x[i];
74 			for (unsigned i = 0;i < HALF_LENGTH;++i) y[i ^ 4] = x[i];
75 			for (unsigned i = 0;i < HALF_LENGTH;++i) x[i] = ROTATE(y[i],11);
76 			for (unsigned i = 0;i < HALF_LENGTH;++i) x[i] ^= x[i + HALF_LENGTH];
77 			for (unsigned i = 0;i < HALF_LENGTH;++i) y[i ^ 1] = x[i + HALF_LENGTH];
78 			for (unsigned i = 0;i < HALF_LENGTH;++i) x[i + HALF_LENGTH] = y[i];
79 		}
80 	}
81 
Init()82 	void Init()
83 	{
84 		if (hashbytelen < 1 || hashbytelen > 64 || hashbytelen > (sizeof hashval/sizeof *hashval))
85 			throw "invalid hash length";
86 		if (!initial_rounds || !block_rounds || !final_rounds)
87 			throw "invalid number of rounds";
88 		if (bytes_per_block < 1 || bytes_per_block > (4U * (sizeof x/sizeof *x)))
89 			throw "invalid number of bytes per block";
90 
91 		x[0] = hashbytelen;
92 		x[1] = bytes_per_block;
93 		x[2] = block_rounds;
94 		for (unsigned i = 3;i < (sizeof x/sizeof *x);++i) x[i] = 0;
95 		transform(initial_rounds);
96 	}
97 };
98