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

Generated by: LCOV version 1.14