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