LCOV - code coverage report
Current view: top level - ballet/bn254 - fd_poseidon.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 109 123 88.6 %
Date: 2026-08-20 04:31:44 Functions: 8 8 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             :                        fd_poseidon_par_t const * params,
      10     1029336 :                        ulong                     round ) {
      11     7399878 :   for( ulong i=0; i<width; i++ ) {
      12     6370542 :     fd_bn254_scalar_add( &state[i], &state[i], &params->ark[ round * width + i ] );
      13     6370542 :   }
      14     1029336 : }
      15             : 
      16             : static inline void
      17             : fd_poseidon_apply_sbox_full( fd_bn254_scalar_t state[],
      18     1029336 :                              ulong const       width ) {
      19             :   /* Compute s[i]^5 */
      20     2662920 :   for( ulong i=0; i<width; i++ ) {
      21     1633584 :     fd_bn254_scalar_t t[1];
      22     1633584 :     fd_bn254_scalar_sqr( t, &state[i] );            /* t = s^2 */
      23     1633584 :     fd_bn254_scalar_sqr( t, t );                    /* t = s^4 */
      24     1633584 :     fd_bn254_scalar_mul( &state[i], &state[i], t ); /* s = s^5 */
      25     1633584 :   }
      26     1029336 : }
      27             : 
      28             : static inline void
      29      908592 : fd_poseidon_apply_sbox_partial( fd_bn254_scalar_t state[] ) {
      30             :   /* Compute s[0]^5 */
      31      908592 :   fd_poseidon_apply_sbox_full( state, 1 );
      32      908592 : }
      33             : 
      34             : static inline void
      35             : fd_poseidon_apply_mds( fd_bn254_scalar_t   state[],
      36             :                        ulong const       width,
      37     1029336 :                        fd_poseidon_par_t const * params ) {
      38     1029336 :   fd_bn254_scalar_t x[FD_POSEIDON_MAX_WIDTH+1] = { 0 };
      39             :   /* Vector-matrix multiplication (state vector times mds matrix) */
      40     7399878 :   for( ulong i=0; i<width; i++ ) {
      41    61832526 :     for( ulong j=0; j<width; j++ ) {
      42    55461984 :       fd_bn254_scalar_t t[1];
      43    55461984 :       fd_bn254_scalar_mul( t, &state[j], &params->mds[ i * width + j ] );
      44    55461984 :       fd_bn254_scalar_add( &x[i], &x[i], t );
      45    55461984 :     }
      46     6370542 :   }
      47     7399878 :   for( ulong i=0; i<width; i++ ) {
      48     6370542 :     state[i] = x[i];
      49     6370542 :   }
      50     1029336 : }
      51             : 
      52             : static inline void
      53             : fd_poseidon_get_params( fd_poseidon_par_t * params,
      54       15093 :                         ulong const         width ) {
      55       15093 : #define FD_POSEIDON_GET_PARAMS(w) case (w):                \
      56       15093 :   params->ark = (fd_bn254_scalar_t *)fd_poseidon_ark_## w; \
      57       15093 :   params->mds = (fd_bn254_scalar_t *)fd_poseidon_mds_## w; \
      58       15093 :   break
      59             : 
      60       15093 :   switch( width ) {
      61        3015 :   FD_POSEIDON_GET_PARAMS(2);
      62        3015 :   FD_POSEIDON_GET_PARAMS(3);
      63           6 :   FD_POSEIDON_GET_PARAMS(4);
      64        3006 :   FD_POSEIDON_GET_PARAMS(5);
      65           6 :   FD_POSEIDON_GET_PARAMS(6);
      66        3006 :   FD_POSEIDON_GET_PARAMS(7);
      67           6 :   FD_POSEIDON_GET_PARAMS(8);
      68           6 :   FD_POSEIDON_GET_PARAMS(9);
      69           6 :   FD_POSEIDON_GET_PARAMS(10);
      70           6 :   FD_POSEIDON_GET_PARAMS(11);
      71           6 :   FD_POSEIDON_GET_PARAMS(12);
      72       15093 :   FD_POSEIDON_GET_PARAMS(13);
      73       15093 :   }
      74       15093 : #undef FD_POSEIDON_GET_PARAMS
      75       15093 : }
      76             : 
      77             : /* Poseidon interface */
      78             : 
      79             : fd_poseidon_t *
      80             : fd_poseidon_init( fd_poseidon_t * pos,
      81       15096 :                   int const       big_endian ) {
      82       15096 :   if( FD_UNLIKELY( pos==NULL ) ) {
      83           0 :     return NULL;
      84           0 :   }
      85       15096 :   pos->big_endian = big_endian;
      86       15096 :   pos->cnt = 0UL;
      87       15096 :   fd_memset( pos->state, 0, sizeof(pos->state) );
      88       15096 :   return pos;
      89       15096 : }
      90             : 
      91             : fd_poseidon_t *
      92             : fd_poseidon_append( fd_poseidon_t * pos,
      93             :                     uchar const *   data,
      94       75534 :                     ulong           sz ) {
      95       75534 :   if( FD_UNLIKELY( pos==NULL ) ) {
      96           0 :     return NULL;
      97           0 :   }
      98       75534 :   if( FD_UNLIKELY( pos->cnt >= FD_POSEIDON_MAX_WIDTH ) ) {
      99           0 :     return NULL;
     100           0 :   }
     101       75534 :   if( FD_UNLIKELY( sz!=32UL ) ) {
     102           3 :     return NULL;
     103           3 :   }
     104             : 
     105             :   /* Handle endianness */
     106       75531 :   fd_bn254_scalar_t cur[1] = { 0 };
     107       75531 :   fd_memcpy( cur->buf, data, 32UL );
     108       75531 :   if( pos->big_endian ) {
     109       75519 :     fd_uint256_bswap( cur, cur );
     110       75519 :   }
     111             : 
     112       75531 :   if( FD_UNLIKELY( !fd_bn254_scalar_validate( cur ) ) ) {
     113           0 :     return NULL;
     114           0 :   }
     115       75531 :   pos->cnt++;
     116       75531 :   fd_bn254_scalar_to_mont( &pos->state[ pos->cnt ], cur );
     117             : 
     118       75531 :   return pos;
     119       75531 : }
     120             : 
     121             : uchar *
     122             : fd_poseidon_fini( fd_poseidon_t * pos,
     123       15093 :                   uchar           hash[ FD_POSEIDON_HASH_SZ ] ) {
     124       15093 :   if( FD_UNLIKELY( pos==NULL ) ) {
     125           0 :     return NULL;
     126           0 :   }
     127       15093 :   if( FD_UNLIKELY( !pos->cnt ) ) {
     128           0 :     return NULL;
     129           0 :   }
     130       15093 :   const ulong width = pos->cnt+1;
     131       15093 :   fd_poseidon_par_t params[1] = { 0 };
     132       15093 :   fd_poseidon_get_params( params, width );
     133       15093 :   if( FD_UNLIKELY( !params->ark || !params->mds ) ) {
     134           0 :     return NULL;
     135           0 :   }
     136             : 
     137       15093 :   const ulong PARTIAL_ROUNDS[] = { 56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68 };
     138       15093 :   const ulong partial_rounds = PARTIAL_ROUNDS[ pos->cnt-1 ];
     139       15093 :   const ulong full_rounds = 8;
     140       15093 :   const ulong half_rounds = full_rounds / 2;
     141       15093 :   const ulong all_rounds = full_rounds + partial_rounds;
     142             : 
     143       15093 :   ulong round=0;
     144       75465 :   for (; round<half_rounds; round++ ) {
     145       60372 :     fd_poseidon_apply_ark         ( pos->state, width, params, round );
     146       60372 :     fd_poseidon_apply_sbox_full   ( pos->state, width );
     147       60372 :     fd_poseidon_apply_mds         ( pos->state, width, params );
     148       60372 :   }
     149             : 
     150      923685 :   for (; round<half_rounds+partial_rounds; round++ ) {
     151      908592 :     fd_poseidon_apply_ark         ( pos->state, width, params, round );
     152      908592 :     fd_poseidon_apply_sbox_partial( pos->state );
     153      908592 :     fd_poseidon_apply_mds         ( pos->state, width, params );
     154      908592 :   }
     155             : 
     156       75465 :   for (; round<all_rounds; round++ ) {
     157       60372 :     fd_poseidon_apply_ark         ( pos->state, width, params, round );
     158       60372 :     fd_poseidon_apply_sbox_full   ( pos->state, width );
     159       60372 :     fd_poseidon_apply_mds         ( pos->state, width, params );
     160       60372 :   }
     161             : 
     162             :   /* Convert through a local scalar: hash only needs to be byte aligned. */
     163       15093 :   fd_bn254_scalar_t scalar_hash[1];
     164       15093 :   fd_bn254_scalar_from_mont( scalar_hash, &pos->state[0] );
     165       15093 :   if( pos->big_endian ) {
     166       15084 :     fd_uint256_bswap( scalar_hash, scalar_hash );
     167       15084 :   }
     168       15093 :   fd_memcpy( hash, scalar_hash, 32 );
     169       15093 :   return hash;
     170       15093 : }

Generated by: LCOV version 1.14