+
+ Line data Source code
+
+ 1 : /*
+ 2 : * Copyright (C) 2026 Andrea Mazzoleni
+ 3 : *
+ 4 : * This program is free software: you can redistribute it and/or modify
+ 5 : * it under the terms of the GNU General Public License as published by
+ 6 : * the Free Software Foundation, either version 3 of the License, or
+ 7 : * (at your option) any later version.
+ 8 : *
+ 9 : * This program is distributed in the hope that it will be useful,
+ 10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ 11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 12 : * GNU General Public License for more details.
+ 13 : *
+ 14 : * You should have received a copy of the GNU General Public License
+ 15 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ 16 : */
+ 17 :
+ 18 : /*
+ 19 : * Derivative work from MuseAir 0.4-rc4 in the "Bfast" configuration
+ 20 : *
+ 21 : * This version extends the original MuseAirLoong to accept a full 128-bit seed.
+ 22 : *
+ 23 : * Note: The original algorithm's behavior can be perfectly replicated by
+ 24 : * setting the low and high part of the seed to the same 64-bit value.
+ 25 : *
+ 26 : * https://github.com/eternal-io/museair
+ 27 : */
+ 28 :
+ 29 : /*
+ 30 : * MuseAir hash algorithm itself and its reference implementation (this file)
+ 31 : * by K--Aethiax are released into the public domain under the CC0 1.0 license.
+ 32 : * To view a copy of this license, visit: https://creativecommons.org/publicdomain/zero/1.0/
+ 33 : */
+ 34 :
+ 35 : #define MUSEAIR_ALGORITHM_VERSION "0.4-rc4"
+ 36 :
+ 37 : #define u64x(N) (N * 8)
+ 38 :
+ 39 : /* AiryAi(0) fractional part calculated by Y-Cruncher */
+ 40 : static const uint64_t MUSEAIR_CONSTANT[7] = {
+ 41 : 0x5ae31e589c56e17aULL,
+ 42 : 0x96d7bb04e64f6da9ULL,
+ 43 : 0x7ab1006b26f9eb64ULL,
+ 44 : 0x21233394220b8457ULL,
+ 45 : 0x047cb9557c9f3b43ULL,
+ 46 : 0xd24f2590c0bcee28ULL,
+ 47 : 0x33ea8f71bb6016d8ULL
+ 48 : };
+ 49 :
+ 50 : #define mult64_128(l, h, a, b) \
+ 51 : do { \
+ 52 : l = a; \
+ 53 : h = b; \
+ 54 : util_mum(&l, &h); \
+ 55 : } while (0)
+ 56 :
+ 57 : #define likely(a) tommy_likely(a)
+ 58 : #define unlikely(a) tommy_unlikely(a)
+ 59 :
+ 60 361 : static void MuseAirLoong(const void* bytes, size_t len, const uint8_t* seed, uint8_t* out)
+ 61 : {
+ 62 361 : const uint8_t* p = bytes;
+ 63 361 : size_t q = len;
+ 64 :
+ 65 : /* EXTENSION: This algo doesn't support shorter lengths */
+ 66 361 : assert(len >= 32);
+ 67 :
+ 68 : uint64_t i, j, k;
+ 69 :
+ 70 361 : uint64_t lo0, lo1, lo2, lo3, lo4, lo5 = MUSEAIR_CONSTANT[6];
+ 71 : uint64_t hi0, hi1, hi2, hi3, hi4, hi5;
+ 72 :
+ 73 : /*
+ 74 : * EXTENSION: Initialize primary state with 128-bit seed (seed0 and seed1)
+ 75 : * Ensures both halves influence the hash.
+ 76 : *
+ 77 : * Original code was:
+ 78 : * uint64_t state[6] = {MUSEAIR_CONSTANT[0] + seed, MUSEAIR_CONSTANT[1] - seed, MUSEAIR_CONSTANT[2] ^ seed,
+ 79 : * MUSEAIR_CONSTANT[3] + seed, MUSEAIR_CONSTANT[4] - seed, MUSEAIR_CONSTANT[5] ^ seed};
+ 80 : */
+ 81 361 : uint64_t seed0 = util_read64(seed);
+ 82 361 : uint64_t seed1 = util_read64(seed + 8);
+ 83 361 : uint64_t state[6] = { MUSEAIR_CONSTANT[0] + seed0, MUSEAIR_CONSTANT[1] - seed1, MUSEAIR_CONSTANT[2] ^ seed0,
+ 84 361 : MUSEAIR_CONSTANT[3] + seed1, MUSEAIR_CONSTANT[4] - seed0, MUSEAIR_CONSTANT[5] ^ seed1 };
+ 85 :
+ 86 361 : if (unlikely(q > u64x(12))) {
+ 87 : do {
+ 88 371504 : state[0] ^= util_read64(p + u64x(0));
+ 89 371504 : state[1] ^= util_read64(p + u64x(1));
+ 90 371504 : mult64_128(lo0, hi0, state[0], state[1]);
+ 91 371504 : state[0] = lo5 ^ hi0;
+ 92 :
+ 93 371504 : state[1] ^= util_read64(p + u64x(2));
+ 94 371504 : state[2] ^= util_read64(p + u64x(3));
+ 95 371504 : mult64_128(lo1, hi1, state[1], state[2]);
+ 96 371504 : state[1] = lo0 ^ hi1;
+ 97 :
+ 98 371504 : state[2] ^= util_read64(p + u64x(4));
+ 99 371504 : state[3] ^= util_read64(p + u64x(5));
+ 100 371504 : mult64_128(lo2, hi2, state[2], state[3]);
+ 101 371504 : state[2] = lo1 ^ hi2;
+ 102 :
+ 103 371504 : state[3] ^= util_read64(p + u64x(6));
+ 104 371504 : state[4] ^= util_read64(p + u64x(7));
+ 105 371504 : mult64_128(lo3, hi3, state[3], state[4]);
+ 106 371504 : state[3] = lo2 ^ hi3;
+ 107 :
+ 108 371504 : state[4] ^= util_read64(p + u64x(8));
+ 109 371504 : state[5] ^= util_read64(p + u64x(9));
+ 110 371504 : mult64_128(lo4, hi4, state[4], state[5]);
+ 111 371504 : state[4] = lo3 ^ hi4;
+ 112 :
+ 113 371504 : state[5] ^= util_read64(p + u64x(10));
+ 114 371504 : state[0] ^= util_read64(p + u64x(11));
+ 115 371504 : mult64_128(lo5, hi5, state[5], state[0]);
+ 116 371504 : state[5] = lo4 ^ hi5;
+ 117 :
+ 118 371504 : p += u64x(12);
+ 119 371504 : q -= u64x(12);
+ 120 :
+ 121 371504 : } while (likely(q > u64x(12)));
+ 122 :
+ 123 296 : state[0] ^= lo5;
+ 124 : }
+ 125 :
+ 126 361 : lo0 = 0, lo1 = 0, lo2 = 0, lo3 = 0, lo4 = 0, lo5 = 0;
+ 127 361 : hi0 = 0, hi1 = 0, hi2 = 0, hi3 = 0, hi4 = 0, hi5 = 0;
+ 128 :
+ 129 361 : if (likely(q > u64x(4))) {
+ 130 296 : state[0] ^= util_read64(p + u64x(0));
+ 131 296 : state[1] ^= util_read64(p + u64x(1));
+ 132 296 : mult64_128(lo0, hi0, state[0], state[1]);
+ 133 :
+ 134 296 : if (likely(q > u64x(6))) {
+ 135 248 : state[1] ^= util_read64(p + u64x(2));
+ 136 248 : state[2] ^= util_read64(p + u64x(3));
+ 137 248 : mult64_128(lo1, hi1, state[1], state[2]);
+ 138 :
+ 139 248 : if (likely(q > u64x(8))) {
+ 140 64 : state[2] ^= util_read64(p + u64x(4));
+ 141 64 : state[3] ^= util_read64(p + u64x(5));
+ 142 64 : mult64_128(lo2, hi2, state[2], state[3]);
+ 143 :
+ 144 64 : if (likely(q > u64x(10))) {
+ 145 32 : state[3] ^= util_read64(p + u64x(6));
+ 146 32 : state[4] ^= util_read64(p + u64x(7));
+ 147 32 : mult64_128(lo3, hi3, state[3], state[4]);
+ 148 : }
+ 149 : }
+ 150 : }
+ 151 : }
+ 152 :
+ 153 361 : state[4] ^= util_read64(p + q - u64x(4));
+ 154 361 : state[5] ^= util_read64(p + q - u64x(3));
+ 155 361 : mult64_128(lo4, hi4, state[4], state[5]);
+ 156 :
+ 157 361 : state[5] ^= util_read64(p + q - u64x(2));
+ 158 361 : state[0] ^= util_read64(p + q - u64x(1));
+ 159 361 : mult64_128(lo5, hi5, state[5], state[0]);
+ 160 :
+ 161 361 : i = state[0] - state[1];
+ 162 361 : j = state[2] - state[3];
+ 163 361 : k = state[4] - state[5];
+ 164 :
+ 165 361 : int rot = len & 63;
+ 166 361 : i = util_rotl64(i, rot);
+ 167 361 : j = util_rotr64(j, rot);
+ 168 361 : k ^= len;
+ 169 :
+ 170 361 : i += lo3 ^ hi3 ^ lo4 ^ hi4;
+ 171 361 : j += lo5 ^ hi5 ^ lo0 ^ hi0;
+ 172 361 : k += lo1 ^ hi1 ^ lo2 ^ hi2;
+ 173 :
+ 174 361 : mult64_128(lo0, hi0, i, j);
+ 175 361 : mult64_128(lo1, hi1, j, k);
+ 176 361 : mult64_128(lo2, hi2, k, i);
+ 177 :
+ 178 361 : util_write64(out, lo0 ^ lo1 ^ hi2);
+ 179 361 : util_write64(out + 8, hi0 ^ hi1 ^ lo2);
+ 180 361 : }
+ 181 :
+
+ |
+
+