LCOV - code coverage report
Current view: top level - ballet/merlin - fd_merlin.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 90 92 97.8 %
Date: 2026-10-22 18:10:43 Functions: 12 12 100.0 %

          Line data    Source code
       1             : #include "fd_merlin.h"
       2             : #include "../keccak256/fd_keccak256_private.h"
       3             : 
       4             : /* Derived from https://github.com/hdevalence/libmerlin */
       5             : 
       6             : /* Strobe-128 Internals */
       7             : 
       8     2828852 : #define STROBE_R 166
       9       10777 : #define FLAG_I (1)
      10      104876 : #define FLAG_A (1 << 1)
      11      115377 : #define FLAG_C (1 << 2)
      12             : #define FLAG_T (1 << 3)
      13       53731 : #define FLAG_M (1 << 4)
      14      104600 : #define FLAG_K (1 << 5)
      15             : 
      16             : static inline void
      17       19920 : strobe128_run_f( fd_merlin_strobe128_t * ctx ) {
      18       19920 :   ctx->state_bytes[ctx->pos] ^= ctx->pos_begin;
      19       19920 :   ctx->state_bytes[ctx->pos + 1] ^= 0x04;
      20       19920 :   ctx->state_bytes[STROBE_R + 1] ^= 0x80;
      21       19920 :   fd_keccak256_core( ctx->state );
      22       19920 :   ctx->pos = 0;
      23       19920 :   ctx->pos_begin = 0;
      24       19920 : }
      25             : 
      26             : static void
      27             : strobe128_absorb( fd_merlin_strobe128_t * ctx,
      28             :                   uchar const *           data,
      29      248818 :                   ulong const             data_len) {
      30     2370120 :   for ( ulong i=0; i<data_len; i++ ) {
      31     2121302 :     ctx->state_bytes[ctx->pos] ^= data[i];
      32     2121302 :     ctx->pos++;
      33     2121302 :     if (ctx->pos == STROBE_R) {
      34        9146 :       strobe128_run_f(ctx);
      35        9146 :     }
      36     2121302 :   }
      37      248818 : }
      38             : 
      39             : static void
      40             : strobe128_squeeze( fd_merlin_strobe128_t * ctx,
      41             :                    uchar *                 data,
      42       10781 :                    ulong const             data_len) {
      43      698411 :   for ( ulong i=0; i<data_len; i++ ) {
      44      687630 :     data[i] = ctx->state_bytes[ctx->pos];
      45      687630 :     ctx->state_bytes[ctx->pos] = 0;
      46      687630 :     ctx->pos++;
      47      687630 :     if (ctx->pos == STROBE_R) {
      48           0 :       strobe128_run_f(ctx);
      49           0 :     }
      50      687630 :   }
      51       10781 : }
      52             : 
      53             : static void
      54             : strobe128_begin_op( fd_merlin_strobe128_t * ctx,
      55      104600 :                     uchar                   flags ) {
      56             :   /* Note: this implementation cuts some corners, see code below.
      57             :      Our implementation of Merlin doesn't use these features. */
      58             : 
      59             :   /*
      60             :   if (more) {
      61             :     // Changing flags while continuing is illegal
      62             :     assert(ctx->cur_flags == flags);
      63             :     return;
      64             :   }
      65             : 
      66             :   // T flag is not supported
      67             :   assert(!(flags & FLAG_T));
      68             :   */
      69             : 
      70      104600 :   uchar old_begin = ctx->pos_begin;
      71      104600 :   ctx->pos_begin = (uchar)(ctx->pos + 1);
      72      104600 :   ctx->cur_flags = flags;
      73             : 
      74      104600 :   uchar data[2] = { old_begin, flags };
      75      104600 :   strobe128_absorb( ctx, data, 2 );
      76             : 
      77             :   /* Force running the permutation if C or K is set. */
      78      104600 :   uchar force_f = 0 != (flags & (FLAG_C | FLAG_K));
      79             : 
      80      104600 :   if (force_f && ctx->pos != 0) {
      81       10778 :     strobe128_run_f(ctx);
      82       10778 :   }
      83      104600 : }
      84             : 
      85             : /* Strobe-128 */
      86             : 
      87             : static inline void
      88             : strobe128_meta_ad( fd_merlin_strobe128_t * ctx,
      89             :                    uchar const *           data,
      90             :                    ulong                   data_len,
      91      104732 :                    uchar                   more ) {
      92      104732 :   if ( more==0 ) {
      93       53731 :     strobe128_begin_op( ctx, FLAG_M | FLAG_A );
      94       53731 :   }
      95      104732 :   strobe128_absorb(   ctx, data, data_len );
      96      104732 : }
      97             : 
      98             : static inline void
      99             : strobe128_ad(fd_merlin_strobe128_t * ctx,
     100             :              uchar const *           data,
     101             :              ulong const             data_len,
     102       40368 :              uchar                   more) {
     103       40368 :   if ( more==0 ) {
     104       40368 :     strobe128_begin_op( ctx, FLAG_A );
     105       40368 :   }
     106       40368 :   strobe128_absorb(   ctx, data, data_len );
     107       40368 : }
     108             : 
     109             : static inline void
     110             : strobe128_prf( fd_merlin_strobe128_t * ctx,
     111             :                uchar *                 data,
     112             :                ulong const             data_len,
     113       10777 :                uchar                   more ) {
     114       10777 :   if ( more==0 ) {
     115       10777 :     strobe128_begin_op(ctx, FLAG_I | FLAG_A | FLAG_C );
     116       10777 :   }
     117       10777 :   strobe128_squeeze(ctx, data, data_len);
     118       10777 : }
     119             : 
     120             : static inline void
     121             : strobe128_init( fd_merlin_strobe128_t * ctx,
     122             :                 uchar const *           label,
     123        2601 :                 ulong const             label_len ) {
     124        2601 :   uchar init[18] = {
     125        2601 :     1,  168, 1,  0,   1,  96, 83, 84, 82,
     126        2601 :     79, 66,  69, 118, 49, 46, 48, 46, 50,
     127        2601 :   };
     128        2601 :   fd_memset( ctx->state_bytes, 0, 200 );
     129        2601 :   fd_memcpy( ctx->state_bytes, init, 18 );
     130        2601 :   fd_keccak256_core( ctx->state );
     131        2601 :   ctx->pos = 0;
     132        2601 :   ctx->pos_begin = 0;
     133        2601 :   ctx->cur_flags = 0;
     134             : 
     135        2601 :   strobe128_meta_ad( ctx, label, label_len, 0 );
     136        2601 : }
     137             : 
     138             : /* Merlin */
     139             : 
     140             : void
     141             : fd_merlin_transcript_init( fd_merlin_transcript_t * mctx,
     142             :                            char const * const       label,
     143        2601 :                            uint const               label_len ) {
     144        2601 :   strobe128_init(&mctx->sctx, (uchar *)FD_MERLIN_LITERAL("Merlin v1.0"));
     145        2601 :   fd_merlin_transcript_append_message(mctx, FD_MERLIN_LITERAL("dom-sep"), (uchar *)label, label_len);
     146        2601 : }
     147             : 
     148             : void
     149             : fd_merlin_transcript_append_message( fd_merlin_transcript_t * mctx,
     150             :                                      char const * const       label,
     151             :                                      uint const               label_len,
     152             :                                      uchar const *            message,
     153       40404 :                                      uint const               message_len ) {
     154       40404 :   strobe128_meta_ad(&mctx->sctx, (uchar *)label, label_len, 0);
     155       40404 :   strobe128_meta_ad(&mctx->sctx, (uchar *)&message_len, 4, 1);
     156       40404 :   strobe128_ad(&mctx->sctx, message, message_len, 0);
     157       40404 : }
     158             : 
     159             : inline void
     160             : fd_merlin_transcript_append_u64( fd_merlin_transcript_t * mctx,
     161             :                                  char const * const       label,
     162             :                                  uint const               label_len,
     163        2522 :                                  ulong const              message_u64 ) {
     164        2522 :   fd_merlin_transcript_append_message( mctx, label, label_len, (uchar *)&message_u64, 8 );
     165        2522 : }
     166             : 
     167             : void
     168             : fd_merlin_transcript_challenge_bytes( fd_merlin_transcript_t * mctx,
     169             :                                       char const * const       label,
     170             :                                       uint const               label_len,
     171             :                                       uchar *                  buffer,
     172       10777 :                                       uint const               buffer_len ) {
     173       10777 :   strobe128_meta_ad(&mctx->sctx, (uchar *)label, label_len, 0);
     174       10777 :   strobe128_meta_ad(&mctx->sctx, (uchar *)&buffer_len, 4, 1);
     175       10777 :   strobe128_prf(&mctx->sctx, buffer, buffer_len, 0);
     176       10777 : }

Generated by: LCOV version 1.14