LCOV - code coverage report
Current view: top level - disco/shred - fd_rnonce_ss.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 40 0.0 %
Date: 2026-03-19 18:19:27 Functions: 0 16 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_disco_shred_fd_rnonce_ss_h
       2             : #define HEADER_fd_src_disco_shred_fd_rnonce_ss_h
       3             : #include "../../util/fd_util.h"
       4             : 
       5             : /* fd_rnonce_ss_t is a strongly typed version of the 64 byte shared
       6             :    secret used to generate and verify nonces for repair requests and
       7             :    responses. */
       8             : union fd_rnonce_ss {
       9             :   uchar bytes[64];
      10             :   struct {
      11             :     ulong ss0[3];
      12             :     ulong slot;
      13             :     ulong ss1[1];
      14             :     uint  shred_idx;
      15             :     uint  ss2[2];
      16             :     uint  time;
      17             :     ulong ss3[1];
      18             :   } private;
      19             : };
      20             : typedef union fd_rnonce_ss fd_rnonce_ss_t;
      21             : FD_STATIC_ASSERT( sizeof(fd_rnonce_ss_t)==64, rnonce_ss );
      22             : 
      23             : FD_PROTOTYPES_BEGIN
      24             : 
      25             : /* fd_rnonce_ss_{compute,verify} compute and verify, respectively, the
      26             :    nonce for the specifed repair request issued or received at time_ns.
      27             :    slot and shred_idx specify the slot and shred index of the
      28             :    requested/received shred.  normal_repair must be non-zero if the
      29             :    request is a "normal" repair request, i.e., one for a specific shred
      30             :    index.  If normal_repair is zero, shred_idx is ignored, and slot is
      31             :    adjusted (see below). ss is a pointer to the shared secret value.
      32             :    ss_compute returns the value of the nonce.  ss_verify takes the
      33             :    supposed value of the nonce in the nonce parameter.  ss_verify
      34             :    returns 1 if the nonce is correct and 0 otherwise.
      35             : 
      36             :    These satisfy:
      37             :    1==ss_verify( ss_v, ss_compute( ss_c, 1, slot_c, shred_idx_c, rq_time ), 1, slot_v, shred_idx_v, rs_time )
      38             :    when
      39             :       ss_v        == ss_c,
      40             :       slot_v      == slot_c,
      41             :       shred_idx_v == shred_idx_c, AND
      42             :       rq_time <= rs_time < rq_time + 1.02 seconds.
      43             :    When any of these of these conditions is false, it should return 0
      44             :    with high probability, approx (1 - 2^25).
      45             : 
      46             :    And
      47             :    1==ss_verify( ss_v, ss_compute( ss_c, 0, slot_c, shred_idx_c, rq_time ), 0, slot_v, shred_idx_v, rs_time )
      48             :    when
      49             :       ss_v        == ss_c,
      50             :       -1 <= floor(slot_v/128) - floor(slot_c/128) <= 0,  which is looser than slot_c - 128 <= slot_v <= slot_c
      51             :       rq_time <= rs_time < rq_time + 1.02 seconds.
      52             :    When any of these of these conditions is false, it should return 0
      53             :    with high probability, approx (1 - 2^25).
      54             : */
      55             : static inline uint
      56             : fd_rnonce_ss_compute( fd_rnonce_ss_t const * ss,
      57             :                       int                    normal_repair,
      58             :                       ulong                  slot,
      59             :                       uint                   shred_idx,
      60           0 :                       long                   time_ns ) {
      61           0 :   fd_rnonce_ss_t temp[1] = { *ss };
      62             :   /* truncate time down to intervals of 2^32 ns, which is ~4 seconds. */
      63           0 :   temp->private.time      = (uint)(time_ns>>32);
      64           0 :   temp->private.slot      = fd_ulong_if( normal_repair, slot,      slot/128UL );
      65           0 :   temp->private.shred_idx = fd_uint_if ( normal_repair, shred_idx, 0U         );
      66             :   /* seed is fractional part of sqrt(17) */
      67             :   /* Then we add back in time_ns>>24 (truncated to 16ms intervals).
      68             :      This is kind of surprising, but it means that we can generate a new
      69             :      nonce when we re-request a specific shred, but we don't need to
      70             :      compute a ton of hashes. */
      71           0 :   return (uint)(
      72           0 :     fd_ulong_if( normal_repair, 0x80000000UL, 0UL ) |
      73           0 :     (0x7FFFFFFFUL & (fd_hash( 2270897969802886507UL, temp, sizeof(temp) ) + (((ulong)time_ns)>>24) ) ) );
      74           0 : }
      75             : 
      76             : static inline int
      77             : fd_rnonce_ss_verify( fd_rnonce_ss_t const * ss,
      78             :                      uint                   nonce,
      79             :                      ulong                  slot,
      80             :                      uint                   shred_idx,
      81           0 :                      long                   time_ns ) {
      82           0 :   fd_rnonce_ss_t temp[1] = { *ss };
      83           0 :   int normal_repair      = !!(nonce>>31);
      84             : 
      85           0 :   temp->private.time      = (uint)(time_ns>>32);
      86           0 :   temp->private.slot      = fd_ulong_if( normal_repair, slot,      slot/128UL );
      87           0 :   temp->private.shred_idx = fd_uint_if ( normal_repair, shred_idx, 0U         );
      88           0 : #define ALLOWED_TIME_DELTA ((uint)((1000000000UL + (1UL<<24) - 1UL)/(1UL<<24)))  /* == 60 */
      89             : 
      90           0 : #define CHECKN( temp ) do{ if( FD_LIKELY(                                                                                       \
      91           0 :                          ( (0x7FFFFFFFUL & (fd_hash( 2270897969802886507UL, temp, sizeof(temp) ) + (((ulong)time_ns)>>24) )) -  \
      92           0 :                            (0x7FFFFFFFUL & nonce) ) <= ALLOWED_TIME_DELTA ) )                                                   \
      93           0 :                              return 1;                                                                                          \
      94           0 :                        } while( 0 )
      95             : 
      96             : 
      97           0 :   CHECKN( temp );
      98             : 
      99           0 :   int try_prev_time = ((time_ns-1000000000L)>>32) != (time_ns>>32);
     100           0 :   if( try_prev_time ) {
     101             :     /* If that doesn't match, check the previous time bucket. */
     102           0 :     temp->private.time--;
     103           0 :     CHECKN( temp );
     104           0 :     temp->private.time++;
     105           0 :   }
     106             : 
     107           0 :   if( FD_UNLIKELY( !normal_repair ) ) {
     108             :     /* Check the next slot bucket */
     109           0 :     temp->private.slot++;
     110           0 :     CHECKN( temp );
     111           0 :     if( try_prev_time ) {
     112             :       /* And check it with the prev time bucket */
     113           0 :       temp->private.time--;
     114           0 :       CHECKN( temp );
     115           0 :     }
     116           0 :   }
     117           0 : #undef CHECKN
     118           0 : #undef ALLOWED_TIME_DELTA
     119           0 :   return 0;
     120           0 : }
     121             : 
     122             : FD_PROTOTYPES_END
     123             : 
     124             : #endif /* HEADER_fd_src_disco_shred_fd_rnonce_ss_h */

Generated by: LCOV version 1.14