LCOV - code coverage report
Current view: top level - ballet/bn254 - fd_poseidon.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 107 123 87.0 %
Date: 2025-07-10 04:52:38 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     1029531 :                        ulong                     round ) {
      11     7400658 :   for( ulong i=0; i<width; i++ ) {
      12     6371127 :     fd_bn254_scalar_add( &state[i], &state[i], &params->ark[ round * width + i ] );
      13     6371127 :   }
      14     1029531 : }
      15             : 
      16             : static inline void
      17             : fd_poseidon_apply_sbox_full( fd_bn254_scalar_t state[],
      18     1029531 :                              ulong const       width ) {
      19             :   /* Compute s[i]^5 */
      20     2663358 :   for( ulong i=0; i<width; i++ ) {
      21     1633827 :     fd_bn254_scalar_t t[1];
      22     1633827 :     fd_bn254_scalar_sqr( t, &state[i] );            /* t = s^2 */
      23     1633827 :     fd_bn254_scalar_sqr( t, t );                    /* t = s^4 */
      24     1633827 :     fd_bn254_scalar_mul( &state[i], &state[i], t ); /* s = s^5 */
      25     1633827 :   }
      26     1029531 : }
      27             : 
      28             : static inline void
      29      908763 : fd_poseidon_apply_sbox_partial( fd_bn254_scalar_t state[] ) {
      30             :   /* Compute s[0]^5 */
      31      908763 :   fd_poseidon_apply_sbox_full( state, 1 );
      32      908763 : }
      33             : 
      34             : static inline void
      35             : fd_poseidon_apply_mds( fd_bn254_scalar_t   state[],
      36             :                        ulong const       width,
      37     1029531 :                        fd_poseidon_par_t const * params ) {
      38     1029531 :   fd_bn254_scalar_t x[FD_POSEIDON_MAX_WIDTH+1] = { 0 };
      39             :   /* Vector-matrix multiplication (state vector times mds matrix) */
      40     7400658 :   for( ulong i=0; i<width; i++ ) {
      41    61834866 :     for( ulong j=0; j<width; j++ ) {
      42    55463739 :       fd_bn254_scalar_t t[1];
      43    55463739 :       fd_bn254_scalar_mul( t, &state[j], &params->mds[ i * width + j ] );
      44    55463739 :       fd_bn254_scalar_add( &x[i], &x[i], t );
      45    55463739 :     }
      46     6371127 :   }
      47     7400658 :   for( ulong i=0; i<width; i++ ) {
      48     6371127 :     state[i] = x[i];
      49     6371127 :   }
      50     1029531 : }
      51             : 
      52             : static inline void
      53             : fd_poseidon_get_params( fd_poseidon_par_t * params,
      54       15096 :                         ulong const         width ) {
      55       15096 : #define FD_POSEIDON_GET_PARAMS(w) case (w):                \
      56       15096 :   params->ark = (fd_bn254_scalar_t *)fd_poseidon_ark_## w; \
      57       15096 :   params->mds = (fd_bn254_scalar_t *)fd_poseidon_mds_## w; \
      58       15096 :   break
      59             : 
      60       15096 :   switch( width ) {
      61        3015 :   FD_POSEIDON_GET_PARAMS(2);
      62        3018 :   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       15096 :   FD_POSEIDON_GET_PARAMS(13);
      73       15096 :   }
      74       15096 : #undef FD_POSEIDON_GET_PARAMS
      75       15096 : }
      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       75537 :                     ulong           sz ) {
      95       75537 :   if( FD_UNLIKELY( pos==NULL ) ) {
      96           0 :     return NULL;
      97           0 :   }
      98       75537 :   if( FD_UNLIKELY( pos->cnt >= FD_POSEIDON_MAX_WIDTH ) ) {
      99           0 :     return NULL;
     100           0 :   }
     101             :   /* Empty input and non-field are errors. Short element is extended with 0s. */
     102       75537 :   if( FD_UNLIKELY( sz==0 || sz>32UL ) ) {
     103           0 :     return NULL;
     104           0 :   }
     105             : 
     106             :   /* Handle endianness */
     107       75537 :   fd_bn254_scalar_t cur[1] = { 0 };
     108       75537 :   fd_memcpy( cur->buf + (32-sz)*(pos->big_endian?1:0), data, sz );
     109       75537 :   if( pos->big_endian ) {
     110       75525 :     fd_uint256_bswap( cur, cur );
     111       75525 :   }
     112             : 
     113       75537 :   if( FD_UNLIKELY( !fd_bn254_scalar_validate( cur ) ) ) {
     114           0 :     return NULL;
     115           0 :   }
     116       75537 :   pos->cnt++;
     117       75537 :   fd_bn254_scalar_to_mont( &pos->state[ pos->cnt ], cur );
     118             : 
     119       75537 :   return pos;
     120       75537 : }
     121             : 
     122             : uchar *
     123             : fd_poseidon_fini( fd_poseidon_t * pos,
     124       15096 :                   uchar           hash[ FD_POSEIDON_HASH_SZ ] ) {
     125       15096 :   if( FD_UNLIKELY( pos==NULL ) ) {
     126           0 :     return NULL;
     127           0 :   }
     128       15096 :   if( FD_UNLIKELY( !pos->cnt ) ) {
     129           0 :     return NULL;
     130           0 :   }
     131       15096 :   const ulong width = pos->cnt+1;
     132       15096 :   fd_poseidon_par_t params[1] = { 0 };
     133       15096 :   fd_poseidon_get_params( params, width );
     134       15096 :   if( FD_UNLIKELY( !params->ark || !params->mds ) ) {
     135           0 :     return NULL;
     136           0 :   }
     137             : 
     138       15096 :   const ulong PARTIAL_ROUNDS[] = { 56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68 };
     139       15096 :   const ulong partial_rounds = PARTIAL_ROUNDS[ pos->cnt-1 ];
     140       15096 :   const ulong full_rounds = 8;
     141       15096 :   const ulong half_rounds = full_rounds / 2;
     142       15096 :   const ulong all_rounds = full_rounds + partial_rounds;
     143             : 
     144       15096 :   ulong round=0;
     145       75480 :   for (; round<half_rounds; round++ ) {
     146       60384 :     fd_poseidon_apply_ark         ( pos->state, width, params, round );
     147       60384 :     fd_poseidon_apply_sbox_full   ( pos->state, width );
     148       60384 :     fd_poseidon_apply_mds         ( pos->state, width, params );
     149       60384 :   }
     150             : 
     151      923859 :   for (; round<half_rounds+partial_rounds; round++ ) {
     152      908763 :     fd_poseidon_apply_ark         ( pos->state, width, params, round );
     153      908763 :     fd_poseidon_apply_sbox_partial( pos->state );
     154      908763 :     fd_poseidon_apply_mds         ( pos->state, width, params );
     155      908763 :   }
     156             : 
     157       75480 :   for (; round<all_rounds; round++ ) {
     158       60384 :     fd_poseidon_apply_ark         ( pos->state, width, params, round );
     159       60384 :     fd_poseidon_apply_sbox_full   ( pos->state, width );
     160       60384 :     fd_poseidon_apply_mds         ( pos->state, width, params );
     161       60384 :   }
     162             : 
     163             :   /* Directly convert scalar into return hash buffer - hash MUST be FD_UINT256_ALIGNED */
     164       15096 :   fd_bn254_scalar_t scalar_hash[1];
     165       15096 :   fd_bn254_scalar_from_mont( scalar_hash, &pos->state[0] );
     166       15096 :   if( pos->big_endian ) {
     167       15087 :     fd_uint256_bswap( scalar_hash, scalar_hash );
     168       15087 :   }
     169       15096 :   fd_memcpy( hash, scalar_hash, 32 );
     170       15096 :   return hash;
     171       15096 : }

Generated by: LCOV version 1.14