LCOV - code coverage report
Current view: top level - ballet/siphash13 - fd_siphash13.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 51 113 45.1 %
Date: 2026-03-19 18:19:27 Functions: 4 6 66.7 %

          Line data    Source code
       1             : #include "fd_siphash13.h"
       2             : 
       3             : /* This code is a modified version of https://github.com/antirez/siphash
       4             :    For further license info see NOTICE in the root of this repo.
       5             : 
       6             :    Copyright (c) 2012-2016 Jean-Philippe Aumasson
       7             :    <jeanphilippe.aumasson@gmail.com>
       8             :    Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
       9             :    Copyright (c) 2017 Salvatore Sanfilippo <antirez@gmail.com>
      10             :    Modified 2023 by Firedancer Contributors */
      11             : 
      12             : static const ulong __attribute__((aligned(64UL)))
      13             : fd_siphash13_initial[4] = {
      14             :   0x736f6d6570736575UL,
      15             :   0x646f72616e646f6dUL,
      16             :   0x6c7967656e657261UL,
      17             :   0x7465646279746573UL,
      18             : };
      19             : 
      20             : fd_siphash13_t *
      21             : fd_siphash13_init( fd_siphash13_t * sip,
      22             :                    ulong            k0,
      23           4 :                    ulong            k1 ) {
      24             : 
      25           4 :   memset( sip, 0, sizeof(fd_siphash13_t) );
      26             : 
      27           4 :   ulong * v = sip->v;
      28             : 
      29           4 :   v[ 0 ] = fd_siphash13_initial[ 0 ];
      30           4 :   v[ 1 ] = fd_siphash13_initial[ 1 ];
      31           4 :   v[ 2 ] = fd_siphash13_initial[ 2 ];
      32           4 :   v[ 3 ] = fd_siphash13_initial[ 3 ];
      33           4 :   v[ 3 ] ^= k1;
      34           4 :   v[ 2 ] ^= k0;
      35           4 :   v[ 1 ] ^= k1;
      36           4 :   v[ 0 ] ^= k0;
      37             : 
      38           4 :   return sip;
      39           4 : }
      40             : 
      41             : static void
      42             : fd_siphash1N_core( ulong         v[ static 4 ],
      43             :                    uchar const * buf,
      44          12 :                    ulong         n ) {
      45          12 :   ulong m;
      46          48 :   for( ulong i=0UL; i<n; i++ ) {
      47          36 :     m = ((ulong const *)buf)[ i ];
      48          36 :     v[ 3 ] ^= m;
      49          36 :     FD_SIPHASH_ROUND( v );
      50          36 :     v[ 0 ] ^= m;
      51          36 :   }
      52          12 : }
      53             : 
      54             : fd_siphash13_t *
      55             : fd_siphash13_append( fd_siphash13_t * sip,
      56             :                      uchar const *    data,
      57           8 :                      ulong            sz ) {
      58             : 
      59           8 :   ulong * v        = sip->v;
      60           8 :   uchar * buf      = sip->buf;
      61           8 :   ulong   buf_used = sip->n & 7UL;
      62             : 
      63           8 :   sip->n += sz;
      64             : 
      65           8 :   if( FD_UNLIKELY( buf_used ) ) { /* optimized for well aligned use of append */
      66             : 
      67             :     /* If the append isn't large enough to complete the current block,
      68             :        buffer these bytes too and return */
      69             : 
      70           0 :     ulong buf_rem = 8UL - buf_used;
      71           0 :     if( FD_UNLIKELY( sz < buf_rem ) ) {
      72           0 :       fd_memcpy( buf + buf_used, data, sz );
      73           0 :       return sip;
      74           0 :     }
      75             : 
      76             :     /* Otherwise, buffer enough leading bytes of data complete the
      77             :        block, update the hash and then continue processing any remaining
      78             :        bytes of data. */
      79             : 
      80           0 :     fd_memcpy( buf + buf_used, data, buf_rem );
      81           0 :     data += buf_rem;
      82           0 :     sz   -= buf_rem;
      83             : 
      84           0 :     fd_siphash1N_core( v, buf, 1UL );
      85           0 :   }
      86             : 
      87             :   /* Append the bulk of the data */
      88             : 
      89           8 :   ulong block_cnt = sz >> 3;
      90           8 :   if( FD_LIKELY( block_cnt ) ) fd_siphash1N_core( v, data, block_cnt );
      91             : 
      92             :   /* Buffer any leftover bytes */
      93             : 
      94           8 :   buf_used = sz & 7UL;
      95           8 :   if( FD_UNLIKELY( buf_used ) )
      96           0 :     fd_memcpy( buf, data + (sz - buf_used), buf_used );
      97             : 
      98           8 :   return sip;
      99           8 : }
     100             : 
     101             : fd_siphash13_t *
     102             : fd_siphash13_append_fast( fd_siphash13_t * sip,
     103             :                           uchar const *    data,
     104           0 :                           ulong            sz ) {
     105             :   /* TODO debug assertions */
     106           0 :   sip->n += sz;
     107           0 :   fd_siphash1N_core( sip->v, data, sz >> 3 );
     108           0 :   return sip;
     109           0 : }
     110             : 
     111             : ulong
     112           4 : fd_siphash13_fini( fd_siphash13_t * sip ) {
     113             : 
     114             :   /* Unpack inputs */
     115             : 
     116           4 :   ulong * v        = sip->v;
     117           4 :   uchar * buf      = sip->buf;
     118           4 :   ulong   n        = sip->n;
     119           4 :   ulong   buf_used = sip->n & 7UL;
     120             : 
     121             :   /* Hash last block */
     122             : 
     123           4 :   ulong b = n<<56UL;
     124           4 :   switch( buf_used ) {
     125           0 :     case 7: b |= ((ulong)buf[6]) << 48; __attribute__((fallthrough));
     126           0 :     case 6: b |= ((ulong)buf[5]) << 40; __attribute__((fallthrough));
     127           0 :     case 5: b |= ((ulong)buf[4]) << 32; __attribute__((fallthrough));
     128           0 :     case 4: b |= ((ulong)buf[3]) << 24; __attribute__((fallthrough));
     129           0 :     case 3: b |= ((ulong)buf[2]) << 16; __attribute__((fallthrough));
     130           0 :     case 2: b |= ((ulong)buf[1]) <<  8; __attribute__((fallthrough));
     131           0 :     case 1: b |= ((ulong)buf[0]); break;
     132           4 :     case 0: break;
     133           4 :   }
     134           4 :   fd_siphash1N_core( v, (uchar const *)&b, 1UL );
     135             : 
     136             :   /* Finalize */
     137             : 
     138           4 :   v[ 2 ] ^= 0xff;
     139           4 :   FD_SIPHASH_ROUND( v );
     140           4 :   FD_SIPHASH_ROUND( v );
     141           4 :   FD_SIPHASH_ROUND( v );
     142           4 :   b = v[ 0 ] ^ v[ 1 ] ^ v[ 2 ] ^ v[ 3 ];
     143           4 :   return b;
     144           4 : }
     145             : 
     146             : FD_FN_PURE ulong
     147             : fd_siphash13_hash( void const * data,
     148             :                    ulong        data_sz,
     149             :                    ulong        k0,
     150           0 :                    ulong        k1 ) {
     151             : 
     152             :   /* Initialize */
     153             : 
     154           0 :   ulong v[ 4 ];
     155           0 :   memcpy( v, fd_siphash13_initial, 32UL );
     156             : 
     157           0 :   v[ 3 ] ^= k1;
     158           0 :   v[ 2 ] ^= k0;
     159           0 :   v[ 1 ] ^= k1;
     160           0 :   v[ 0 ] ^= k0;
     161             : 
     162             :   /* Hash blocks */
     163             : 
     164           0 :   ulong m;
     165           0 :   ulong const * in    = (ulong const *)data;
     166           0 :   ulong const * end   = in + data_sz/8UL;
     167           0 :   for( ; in!=end; in++ ) {
     168           0 :     m = *in;
     169           0 :     v[ 3 ] ^= m;
     170           0 :     FD_SIPHASH_ROUND( v );
     171           0 :     v[ 0 ] ^= m;
     172           0 :   }
     173             : 
     174             :   /* Hash last block */
     175             : 
     176           0 :   int const     left = data_sz & 7;
     177           0 :   ulong         b    = ((ulong)data_sz) << 56;
     178           0 :   uchar const * rem  = (uchar const *)in;
     179           0 :   switch( left ) {
     180           0 :     case 7: b |= ((ulong)rem[6]) << 48; __attribute__((fallthrough));
     181           0 :     case 6: b |= ((ulong)rem[5]) << 40; __attribute__((fallthrough));
     182           0 :     case 5: b |= ((ulong)rem[4]) << 32; __attribute__((fallthrough));
     183           0 :     case 4: b |= ((ulong)rem[3]) << 24; __attribute__((fallthrough));
     184           0 :     case 3: b |= ((ulong)rem[2]) << 16; __attribute__((fallthrough));
     185           0 :     case 2: b |= ((ulong)rem[1]) <<  8; __attribute__((fallthrough));
     186           0 :     case 1: b |= ((ulong)rem[0]); break;
     187           0 :     case 0: break;
     188           0 :   }
     189             : 
     190           0 :   v[ 3 ] ^= b;
     191           0 :   FD_SIPHASH_ROUND( v );
     192           0 :   v[ 0 ] ^= b;
     193             : 
     194             :   /* Finalize */
     195             : 
     196           0 :   v[ 2 ] ^= 0xff;
     197           0 :   FD_SIPHASH_ROUND( v );
     198           0 :   FD_SIPHASH_ROUND( v );
     199           0 :   FD_SIPHASH_ROUND( v );
     200           0 :   b = v[ 0 ] ^ v[ 1 ] ^ v[ 2 ] ^ v[ 3 ];
     201             : 
     202           0 :   return b;
     203           0 : }

Generated by: LCOV version 1.14