LCOV - code coverage report
Current view: top level - cmdline - museair.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 78 78 100.0 %
Date: 2026-03-15 15:58:19 Functions: 1 1 100.0 %

          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             : 

Generated by: LCOV version 1.0