Line data Source code
1 : #include "fd_merlin.h"
2 : #include "../../../../../ballet/keccak256/fd_keccak256_private.h"
3 :
4 : /* Derived from https://github.com/hdevalence/libmerlin */
5 :
6 : /* Strobe-128 Internals */
7 :
8 4014 : #define STROBE_R 166
9 18 : #define FLAG_I (1)
10 186 : #define FLAG_A (1 << 1)
11 204 : #define FLAG_C (1 << 2)
12 : #define FLAG_T (1 << 3)
13 102 : #define FLAG_M (1 << 4)
14 186 : #define FLAG_K (1 << 5)
15 :
16 : static inline void
17 33 : strobe128_run_f( fd_merlin_strobe128_t * ctx ) {
18 33 : ctx->state_bytes[ctx->pos] ^= ctx->pos_begin;
19 33 : ctx->state_bytes[ctx->pos + 1] ^= 0x04;
20 33 : ctx->state_bytes[STROBE_R + 1] ^= 0x80;
21 33 : fd_keccak256_core( ctx->state );
22 33 : ctx->pos = 0;
23 33 : ctx->pos_begin = 0;
24 33 : }
25 :
26 : static void
27 : strobe128_absorb( fd_merlin_strobe128_t * ctx,
28 : uchar const * data,
29 438 : ulong const data_len) {
30 3363 : for ( ulong i=0; i<data_len; i++ ) {
31 2925 : ctx->state_bytes[ctx->pos] ^= data[i];
32 2925 : ctx->pos++;
33 2925 : if (ctx->pos == STROBE_R) {
34 15 : strobe128_run_f(ctx);
35 15 : }
36 2925 : }
37 438 : }
38 :
39 : static void
40 : strobe128_squeeze( fd_merlin_strobe128_t * ctx,
41 : uchar * data,
42 18 : ulong const data_len) {
43 1074 : for ( ulong i=0; i<data_len; i++ ) {
44 1056 : data[i] = ctx->state_bytes[ctx->pos];
45 1056 : ctx->state_bytes[ctx->pos] = 0;
46 1056 : ctx->pos++;
47 1056 : if (ctx->pos == STROBE_R) {
48 0 : strobe128_run_f(ctx);
49 0 : }
50 1056 : }
51 18 : }
52 :
53 : static void
54 : strobe128_begin_op( fd_merlin_strobe128_t * ctx,
55 186 : 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 186 : uchar old_begin = ctx->pos_begin;
71 186 : ctx->pos_begin = (uchar)(ctx->pos + 1);
72 186 : ctx->cur_flags = flags;
73 :
74 186 : uchar data[2] = { old_begin, flags };
75 186 : strobe128_absorb( ctx, data, 2 );
76 :
77 : /* Force running the permutation if C or K is set. */
78 186 : uchar force_f = 0 != (flags & (FLAG_C | FLAG_K));
79 :
80 186 : if (force_f && ctx->pos != 0) {
81 18 : strobe128_run_f(ctx);
82 18 : }
83 186 : }
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 186 : uchar more ) {
92 186 : if ( more==0 ) {
93 102 : strobe128_begin_op( ctx, FLAG_M | FLAG_A );
94 102 : }
95 186 : strobe128_absorb( ctx, data, data_len );
96 186 : }
97 :
98 : static inline void
99 : strobe128_ad(fd_merlin_strobe128_t * ctx,
100 : uchar const * data,
101 : ulong const data_len,
102 66 : uchar more) {
103 66 : if ( more==0 ) {
104 66 : strobe128_begin_op( ctx, FLAG_A );
105 66 : }
106 66 : strobe128_absorb( ctx, data, data_len );
107 66 : }
108 :
109 : static inline void
110 : strobe128_prf( fd_merlin_strobe128_t * ctx,
111 : uchar * data,
112 : ulong const data_len,
113 18 : uchar more ) {
114 18 : if ( more==0 ) {
115 18 : strobe128_begin_op(ctx, FLAG_I | FLAG_A | FLAG_C );
116 18 : }
117 18 : strobe128_squeeze(ctx, data, data_len);
118 18 : }
119 :
120 : static inline void
121 : strobe128_init( fd_merlin_strobe128_t * ctx,
122 : uchar const * label,
123 18 : ulong const label_len ) {
124 18 : uchar init[18] = {
125 18 : 1, 168, 1, 0, 1, 96, 83, 84, 82,
126 18 : 79, 66, 69, 118, 49, 46, 48, 46, 50,
127 18 : };
128 18 : fd_memset( ctx->state_bytes, 0, 200 );
129 18 : fd_memcpy( ctx->state_bytes, init, 18 );
130 18 : fd_keccak256_core( ctx->state );
131 18 : ctx->pos = 0;
132 18 : ctx->pos_begin = 0;
133 18 : ctx->cur_flags = 0;
134 :
135 18 : strobe128_meta_ad( ctx, label, label_len, 0 );
136 18 : }
137 :
138 : /* Merlin */
139 :
140 : void
141 : fd_merlin_transcript_init( fd_merlin_transcript_t * mctx,
142 : char const * const label,
143 18 : uint const label_len ) {
144 18 : strobe128_init(&mctx->sctx, (uchar *)FD_MERLIN_LITERAL("Merlin v1.0"));
145 18 : fd_merlin_transcript_append_message(mctx, FD_MERLIN_LITERAL("dom-sep"), (uchar *)label, label_len);
146 18 : }
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 66 : uint const message_len ) {
154 66 : strobe128_meta_ad(&mctx->sctx, (uchar *)label, label_len, 0);
155 66 : strobe128_meta_ad(&mctx->sctx, (uchar *)&message_len, 4, 1);
156 66 : strobe128_ad(&mctx->sctx, message, message_len, 0);
157 66 : }
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 0 : ulong const message_u64 ) {
164 0 : fd_merlin_transcript_append_message( mctx, label, label_len, (uchar *)&message_u64, 8 );
165 0 : }
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 18 : uint const buffer_len ) {
173 18 : strobe128_meta_ad(&mctx->sctx, (uchar *)label, label_len, 0);
174 18 : strobe128_meta_ad(&mctx->sctx, (uchar *)&buffer_len, 4, 1);
175 18 : strobe128_prf(&mctx->sctx, buffer, buffer_len, 0);
176 18 : }
|