Rule of Thumb: Don't roll your own encryption--I'm no cryptographer obviously. Also note my apologies for my awful C-style C++.
For a fun little project I've written my own hash algorithm as a practice project. The goal was to write an algorithm that took an input digest
and gave me a generally unique output hash
in the scope of 1024
bits per hash. I believe I've achieved something along those lines. On top of that the idea was to base the hash on as much of the digest as possible--theoretically making the hash more unique.
As far as I can tell I've accomplished two things:
- The avalanche affect.
- Basic level: general uniqueness (to some degree however much or little that may be actually turn out to be...).
The idea behind the algorithm is pretty simple. I stole some things from SHA-512 (SIGMA0/1, ROT macros and prime cuberoots). From there I setup the algorithm in two steps where I largely based the the hash on the data in the actual digest. All rotations and iterations in the hash are based on the data in the digest. The idea was that it'd be harder to find a collision if more of the hash is based on the actual digest.
/* XOR: exclusive-or. SUB: subtract ADD: add ROT: rotate N/NOT: bit-wise NOT. R/L: right/left. FBA: Fast byte/bit alignment of powers of 2. */ #ifndef CUBE_HASH #define CUBE_HASH // Align some data by n (where n is some power of 2). #define FBA(i,n) ((i + (n-1)) & ~(n-1)) // Rotate bits and also bitwise NOT rotated bits by a rotation of 0 <= N < 64. #define NROTR(i,n) ~((i >> n) | (i << (sizeof(__uint64) - n))) #define NROTL(i,n) ~((i << n) | (i >> (sizeof(__uint64) - n))) #define ROTR(i,n) ((i >> n) | (i << (sizeof(__uint64) - n))) #define ROTL(i,n) ((i << n) | (i >> (sizeof(__uint64) - n))) // MOD(i,p) returns i MOD 2^p and does not work on negative numbers. #define MOD(i,p) (i & ((1 << p) - 1)) // SEE: SHA-512 for SGMA0, SIGMA1 uses ~ROTR for it's first rotation (SHA-512 doesn't). #define SGMA0(x) (ROTR(x,7) ^ ROTR(x,18) ^ ROTR(x,3)) #define SGMA1(x) (NROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) #define SGMA2(x) (NROTR(x,25) ^ ROTL(x,43) ^ NROTR(x,9)) typedef unsigned __int64 __uint64; /* The 64 fractional parts of the cuberoots of the first 64 prime numbers. */ const __uint64 fractional_cuberoots[64]{ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b }; /* The 16 fractional parts of the cuberoots of the first 64 prime numbers. */ const __uint64 fractional_cubehash[16]{ 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4 }; class CUBE1024 { public: static __uint64* hash(const __int8* message) { /* NOTE: MOD(i,p) because the macro returns: (i % (2^p)) in bitwise (i & ((1 << p) - 1)). Find the digets length aligned to 1024 bits--128 bytes. */ size_t message_length = strlen(message), digest_length = FBA(message_length + 8, 128); /* Make sure both arrays rae zero'd out: (). Build the array of 16--64-bit base hash values. Allocate the digest. */ __uint64* cube_hash = new __uint64[16](); memcpy(cube_hash, fractional_cubehash, 16); /* Allocate the digest and copy the message into the digest array and append the ~length of the message to the end. */ __uint64* digest = new __uint64[digest_length](); memcpy(digest, message, message_length); digest[digest_length - 1] = NROTR(message_length, MOD(message_length, 3)); size_t z; for (size_t i = 0; i < digest_length; i++) { /* Z: (i + 1) if Z > digest_length, Z wraps back to 0 due to modulo digest_length. Two Steps: XOR the current digest block with the current digets block NOTR of by N-bits which is then SUB by the the SIGMA0 of the current digets block. The current digest block digested the next(i + 1) digest block in the previous step. We don't want to use this same data again. So we ADD the current digest block by it's XOR of the NOT of the SIGMA0 of the current cube_hash where the current cube_hash is i % 16 (the cube hash array is only 16 entries long, so we wrap i). */ z = MOD(i + 1, digest_length); digest[i] ^= NROTR(digest[z], MOD(digest[i], z)) - SGMA0(digest[i]); digest[z] += digest[i] ^ ~SGMA1(cube_hash[MOD(i, 4)]); } size_t x, y; for (size_t i = 0; i < 64; i++) { /* NOTE: We previosuly loaded in all of the fractional_cubehash[0...15] in the cube_hash array before the loop. X: (i) if X > 16, X wraps back to 0 due to modulo 16 (1 << 4). Y: i,n) if y > V, Y wraps back to 0 due to modulo 64. Where V is the ROTR of the cube_hash[x] % B. Where B is the cube[16 - x] % 64. Three Steps: XOR the current cube_hash by the the NROTL of the fractional_cuberoots[y] OR'd by the constant fractional_cubehash[x]. We previously consumed the NROTL of the cuberoot, so now we'll use the NOT of the cuberoot. So we ADD the NOT of the fractional_cuberoot[y] ADD SIGMA2 of the current digest[V] Where V is the i % digest_length. NOTE: if the digest_length > 64, we may not consume the whole digets in this loop. Finally XOR the NROTL of the cube_hash[x] by 2-bytes ADD the opposite fracitonal_cuberoot[64 - i]. */ x = MOD(i, 4); y = MOD(ROTR(cube_hash[x], MOD(cube_hash[16 - x], 6)), 6); cube_hash[x] ^= NROTL(fractional_cuberoots[y], y) | fractional_cubehash[x]; cube_hash[x] += ~fractional_cuberoots[y] + SGMA2(digest[MOD(i, digest_length)]); cube_hash[x] ^= NROTL(cube_hash[x], 16) + fractional_cuberoots[64 - i]; } /* Cleanup the digest. */ delete[] digest; return cube_hash; }; }; #endif
<cstdint>
defines fixed width integers which, although not the prettiest, still look better and are more portable than the ones with two leading underscores used in your code.\$\endgroup\$