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

Generated by: LCOV version 1.14