LCOV - code coverage report
Current view: top level - ballet/bn254 - fd_poseidon.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 168 183 91.8 %
Date: 2026-10-18 04:43:39 Functions: 11 11 100.0 %

          Line data    Source code
       1             : #include "./fd_poseidon.h"
       2             : #include "fd_poseidon_params.c"
       3             : 
       4             : /* Poseidon internals */
       5             : 
       6             : static inline void
       7             : fd_poseidon_apply_ark( fd_bn254_scalar_t         state[],
       8             :                        ulong const               width,
       9      120744 :                        fd_bn254_scalar_t const * ark ) {
      10      845736 :   for( ulong i=0; i<width; i++ ) {
      11      724992 :     fd_bn254_scalar_add( &state[i], &state[i], &ark[i] );
      12      724992 :   }
      13      120744 : }
      14             : 
      15             : static inline void
      16             : fd_poseidon_apply_sbox_full( fd_bn254_scalar_t state[],
      17     1029336 :                              ulong const       width ) {
      18             :   /* Compute s[i]^5 */
      19     2662920 :   for( ulong i=0; i<width; i++ ) {
      20     1633584 :     fd_bn254_scalar_t t[1];
      21     1633584 :     fd_bn254_scalar_sqr( t, &state[i] );            /* t = s^2 */
      22     1633584 :     fd_bn254_scalar_sqr( t, t );                    /* t = s^4 */
      23     1633584 :     fd_bn254_scalar_mul( &state[i], &state[i], t ); /* s = s^5 */
      24     1633584 :   }
      25     1029336 : }
      26             : 
      27             : static inline void
      28      908592 : fd_poseidon_apply_sbox_partial( fd_bn254_scalar_t state[] ) {
      29             :   /* Compute s[0]^5 */
      30      908592 :   fd_poseidon_apply_sbox_full( state, 1 );
      31      908592 : }
      32             : 
      33             : static inline void
      34             : fd_poseidon_apply_mds( fd_bn254_scalar_t         state[],
      35             :                        ulong const               width,
      36      105651 :                        fd_bn254_scalar_t const * mds ) {
      37      105651 :   fd_bn254_scalar_t x[FD_POSEIDON_MAX_WIDTH+1] = { 0 };
      38             :   /* Vector-matrix multiplication (state vector times mds matrix) */
      39      740019 :   for( ulong i=0; i<width; i++ ) {
      40     6049092 :     for( ulong j=0; j<width; j++ ) {
      41     5414724 :       fd_bn254_scalar_t t[1];
      42     5414724 :       fd_bn254_scalar_mul( t, &state[j], &mds[ i * width + j ] );
      43     5414724 :       fd_bn254_scalar_add( &x[i], &x[i], t );
      44     5414724 :     }
      45      634368 :   }
      46      740019 :   for( ulong i=0; i<width; i++ ) {
      47      634368 :     state[i] = x[i];
      48      634368 :   }
      49      105651 : }
      50             : 
      51             : static inline void
      52             : fd_poseidon_apply_sparse_mds( fd_bn254_scalar_t         state[],
      53             :                               ulong const               width,
      54             :                               fd_bn254_scalar_t const * row,
      55      908592 :                               fd_bn254_scalar_t const * col ) {
      56      908592 :   fd_bn254_scalar_t old_s0 = state[0];
      57      908592 :   fd_bn254_scalar_t new_s0[1] = { 0 };
      58             : 
      59     6554142 :   for( ulong j=0; j<width; j++ ) {
      60     5645550 :     fd_bn254_scalar_t t[1];
      61     5645550 :     fd_bn254_scalar_mul( t, &state[j], &row[j] );
      62     5645550 :     fd_bn254_scalar_add( new_s0, new_s0, t );
      63     5645550 :   }
      64             : 
      65     5645550 :   for( ulong i=1; i<width; i++ ) {
      66     4736958 :     fd_bn254_scalar_t t[1];
      67     4736958 :     fd_bn254_scalar_mul( t, &old_s0, &col[i-1] );
      68     4736958 :     fd_bn254_scalar_add( &state[i], &state[i], t );
      69     4736958 :   }
      70             : 
      71      908592 :   state[0] = new_s0[0];
      72      908592 : }
      73             : 
      74             : static inline void
      75             : fd_poseidon_apply_mds_row0( fd_bn254_scalar_t         state[],
      76             :                             ulong const               width,
      77       15093 :                             fd_bn254_scalar_t const * mds ) {
      78       15093 :   fd_bn254_scalar_t new_s0[1] = { 0 };
      79             : 
      80      105717 :   for( ulong j=0; j<width; j++ ) {
      81       90624 :     fd_bn254_scalar_t t[1];
      82       90624 :     fd_bn254_scalar_mul( t, &state[j], &mds[j] );
      83       90624 :     fd_bn254_scalar_add( new_s0, new_s0, t );
      84       90624 :   }
      85             : 
      86       15093 :   state[0] = new_s0[0];
      87       15093 : }
      88             : 
      89             : static inline __attribute__((always_inline)) void
      90             : fd_poseidon_permute( fd_bn254_scalar_t         state[],
      91             :                      ulong const               width,
      92             :                      fd_poseidon_par_t const * params,
      93       15093 :                      ulong const               partial_rounds ) {
      94       15093 :   const ulong half_rounds = 4UL;
      95             : 
      96       15093 :   fd_poseidon_apply_ark       ( state, width, params->ark_start );
      97       15093 :   fd_poseidon_apply_sbox_full ( state, width );
      98             : 
      99       60372 :   for( ulong round=1; round<half_rounds; round++ ) {
     100       45279 :     fd_poseidon_apply_ark       ( state, width, params->ark_start + round*width );
     101       45279 :     fd_poseidon_apply_mds       ( state, width, params->mds );
     102       45279 :     fd_poseidon_apply_sbox_full ( state, width );
     103       45279 :   }
     104             : 
     105       15093 :   fd_poseidon_apply_ark ( state, width, params->ark_start + half_rounds*width );
     106       15093 :   fd_poseidon_apply_mds ( state, width, params->pre_sparse_mds );
     107             : 
     108      923685 :   for( ulong round=0; round<partial_rounds; round++ ) {
     109      908592 :     fd_poseidon_apply_sbox_partial( state );
     110      908592 :     fd_bn254_scalar_add( &state[0], &state[0], &params->ark_partial[ round ] );
     111      908592 :     fd_poseidon_apply_sparse_mds( state,
     112      908592 :                                   width,
     113      908592 :                                   params->sparse_mds_row + round*width,
     114      908592 :                                   params->sparse_mds_col + round*(width-1UL) );
     115      908592 :   }
     116             : 
     117       15093 :   fd_poseidon_apply_sbox_full( state, width );
     118       60372 :   for( ulong round=0; round<half_rounds-1UL; round++ ) {
     119       45279 :     fd_poseidon_apply_ark       ( state, width, params->ark_end + round*width );
     120       45279 :     fd_poseidon_apply_mds       ( state, width, params->mds );
     121       45279 :     fd_poseidon_apply_sbox_full ( state, width );
     122       45279 :   }
     123       15093 :   fd_poseidon_apply_mds_row0( state, width, params->mds );
     124       15093 : }
     125             : 
     126             : static inline void
     127             : fd_poseidon_get_params( fd_poseidon_par_t * params,
     128       15093 :                         ulong const         width ) {
     129       15093 : #define FD_POSEIDON_GET_PARAMS(w) case (w):                       \
     130       15093 :   params->ark            = fd_poseidon_ark_## w;                  \
     131       15093 :   params->mds            = fd_poseidon_mds_## w;                  \
     132       15093 :   params->ark_start      = fd_poseidon_ark_start_## w;            \
     133       15093 :   params->ark_partial    = fd_poseidon_ark_partial_## w;          \
     134       15093 :   params->ark_end        = fd_poseidon_ark_end_## w;              \
     135       15093 :   params->pre_sparse_mds = fd_poseidon_pre_sparse_mds_## w;       \
     136       15093 :   params->sparse_mds_row = fd_poseidon_sparse_mds_row_## w;       \
     137       15093 :   params->sparse_mds_col = fd_poseidon_sparse_mds_col_## w;       \
     138       15093 :   break
     139             : 
     140       15093 :   switch( width ) {
     141        3015 :   FD_POSEIDON_GET_PARAMS(2);
     142        3015 :   FD_POSEIDON_GET_PARAMS(3);
     143           6 :   FD_POSEIDON_GET_PARAMS(4);
     144        3006 :   FD_POSEIDON_GET_PARAMS(5);
     145           6 :   FD_POSEIDON_GET_PARAMS(6);
     146        3006 :   FD_POSEIDON_GET_PARAMS(7);
     147           6 :   FD_POSEIDON_GET_PARAMS(8);
     148           6 :   FD_POSEIDON_GET_PARAMS(9);
     149           6 :   FD_POSEIDON_GET_PARAMS(10);
     150           6 :   FD_POSEIDON_GET_PARAMS(11);
     151           6 :   FD_POSEIDON_GET_PARAMS(12);
     152       15093 :   FD_POSEIDON_GET_PARAMS(13);
     153       15093 :   }
     154       15093 : #undef FD_POSEIDON_GET_PARAMS
     155       15093 : }
     156             : 
     157             : /* Poseidon interface */
     158             : 
     159             : fd_poseidon_t *
     160             : fd_poseidon_init( fd_poseidon_t * pos,
     161       15096 :                   int const       big_endian ) {
     162       15096 :   if( FD_UNLIKELY( pos==NULL ) ) {
     163           0 :     return NULL;
     164           0 :   }
     165       15096 :   pos->big_endian = big_endian;
     166       15096 :   pos->cnt = 0UL;
     167       15096 :   fd_memset( pos->state, 0, sizeof(pos->state) );
     168       15096 :   return pos;
     169       15096 : }
     170             : 
     171             : fd_poseidon_t *
     172             : fd_poseidon_append( fd_poseidon_t * pos,
     173             :                     uchar const *   data,
     174       75534 :                     ulong           sz ) {
     175       75534 :   if( FD_UNLIKELY( pos==NULL ) ) {
     176           0 :     return NULL;
     177           0 :   }
     178       75534 :   if( FD_UNLIKELY( pos->cnt >= FD_POSEIDON_MAX_WIDTH ) ) {
     179           0 :     return NULL;
     180           0 :   }
     181       75534 :   if( FD_UNLIKELY( sz!=32UL ) ) {
     182           3 :     return NULL;
     183           3 :   }
     184             : 
     185             :   /* Handle endianness */
     186       75531 :   fd_bn254_scalar_t cur[1] = { 0 };
     187       75531 :   fd_memcpy( cur->buf, data, 32UL );
     188       75531 :   if( pos->big_endian ) {
     189       75519 :     fd_uint256_bswap( cur, cur );
     190       75519 :   }
     191             : 
     192       75531 :   if( FD_UNLIKELY( !fd_bn254_scalar_validate( cur ) ) ) {
     193           0 :     return NULL;
     194           0 :   }
     195       75531 :   pos->cnt++;
     196       75531 :   fd_bn254_scalar_to_mont( &pos->state[ pos->cnt ], cur );
     197             : 
     198       75531 :   return pos;
     199       75531 : }
     200             : 
     201             : uchar *
     202             : fd_poseidon_fini( fd_poseidon_t * pos,
     203       15093 :                   uchar           hash[ FD_POSEIDON_HASH_SZ ] ) {
     204       15093 :   if( FD_UNLIKELY( pos==NULL ) ) {
     205           0 :     return NULL;
     206           0 :   }
     207       15093 :   if( FD_UNLIKELY( !pos->cnt ) ) {
     208           0 :     return NULL;
     209           0 :   }
     210       15093 :   const ulong width = pos->cnt+1;
     211       15093 :   fd_poseidon_par_t params[1] = { 0 };
     212       15093 :   fd_poseidon_get_params( params, width );
     213       15093 :   if( FD_UNLIKELY( !params->ark            ||
     214       15093 :                    !params->mds            ||
     215       15093 :                    !params->ark_start      ||
     216       15093 :                    !params->ark_partial    ||
     217       15093 :                    !params->ark_end        ||
     218       15093 :                    !params->pre_sparse_mds ||
     219       15093 :                    !params->sparse_mds_row ||
     220       15093 :                    !params->sparse_mds_col ) ) {
     221           0 :     return NULL;
     222           0 :   }
     223             : 
     224       15093 : #define FD_POSEIDON_PERMUTE_CASE(w,p) case (w): fd_poseidon_permute( pos->state, (w), params, (p) ); break
     225       15093 :   switch( width ) {
     226        3015 :   FD_POSEIDON_PERMUTE_CASE( 2UL,  56UL );
     227        3015 :   FD_POSEIDON_PERMUTE_CASE( 3UL,  57UL );
     228           6 :   FD_POSEIDON_PERMUTE_CASE( 4UL,  56UL );
     229        3006 :   FD_POSEIDON_PERMUTE_CASE( 5UL,  60UL );
     230           6 :   FD_POSEIDON_PERMUTE_CASE( 6UL,  60UL );
     231        3006 :   FD_POSEIDON_PERMUTE_CASE( 7UL,  63UL );
     232           6 :   FD_POSEIDON_PERMUTE_CASE( 8UL,  64UL );
     233           6 :   FD_POSEIDON_PERMUTE_CASE( 9UL,  63UL );
     234           6 :   FD_POSEIDON_PERMUTE_CASE( 10UL, 60UL );
     235           6 :   FD_POSEIDON_PERMUTE_CASE( 11UL, 66UL );
     236           6 :   FD_POSEIDON_PERMUTE_CASE( 12UL, 60UL );
     237        3009 :   FD_POSEIDON_PERMUTE_CASE( 13UL, 65UL );
     238           0 :   default: return NULL;
     239       15093 :   }
     240       15093 : #undef FD_POSEIDON_PERMUTE_CASE
     241             : 
     242             :   /* Convert through a local scalar: hash only needs to be byte aligned. */
     243       15093 :   fd_bn254_scalar_t scalar_hash[1];
     244       15093 :   fd_bn254_scalar_from_mont( scalar_hash, &pos->state[0] );
     245       15093 :   if( pos->big_endian ) {
     246       15084 :     fd_uint256_bswap( scalar_hash, scalar_hash );
     247       15084 :   }
     248       15093 :   fd_memcpy( hash, scalar_hash, 32 );
     249       15093 :   return hash;
     250       15093 : }

Generated by: LCOV version 1.14