@deroll/cmio 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/AUTHORS +1 -0
  2. package/LICENSE +202 -0
  3. package/README.md +122 -0
  4. package/binding.gyp +53 -0
  5. package/deps/machine-guest-tools/AUTHORS +7 -0
  6. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/abi.h +589 -0
  7. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/buf.h +82 -0
  8. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/io.h +168 -0
  9. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/keccak.h +131 -0
  10. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/merkle.h +118 -0
  11. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/rollup.h +260 -0
  12. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/util.h +34 -0
  13. package/deps/machine-guest-tools/sys-utils/libcmt/src/abi.c +315 -0
  14. package/deps/machine-guest-tools/sys-utils/libcmt/src/buf.c +121 -0
  15. package/deps/machine-guest-tools/sys-utils/libcmt/src/io-mock.c +319 -0
  16. package/deps/machine-guest-tools/sys-utils/libcmt/src/io.c +164 -0
  17. package/deps/machine-guest-tools/sys-utils/libcmt/src/keccak.c +156 -0
  18. package/deps/machine-guest-tools/sys-utils/libcmt/src/merkle.c +202 -0
  19. package/deps/machine-guest-tools/sys-utils/libcmt/src/rollup.c +455 -0
  20. package/deps/machine-guest-tools/sys-utils/libcmt/src/util.c +52 -0
  21. package/lib/index.d.mts +18 -0
  22. package/lib/index.d.ts +162 -0
  23. package/lib/index.js +230 -0
  24. package/lib/index.mjs +19 -0
  25. package/package.json +70 -0
  26. package/prebuilds/darwin-arm64/@deroll+cmio.node +0 -0
  27. package/src/addon.cc +411 -0
@@ -0,0 +1,319 @@
1
+ /* Copyright Cartesi and individual authors (see AUTHORS)
2
+ * SPDX-License-Identifier: Apache-2.0
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ #include "libcmt/io.h"
17
+ #include "libcmt/util.h"
18
+
19
+ #include <errno.h>
20
+ #include <stdio.h>
21
+ #include <stdlib.h>
22
+ #include <string.h>
23
+
24
+ /** track the number of open "devices". Mimic the kernel driver behavior by limiting it to 1 */
25
+ static int open_count = 0;
26
+
27
+ int cmt_io_init(cmt_io_driver_t *_me) {
28
+ if (!_me) {
29
+ return -EINVAL;
30
+ }
31
+ if (open_count) {
32
+ return -EBUSY;
33
+ }
34
+
35
+ open_count++;
36
+ cmt_io_driver_mock_t *me = &_me->mock;
37
+
38
+ size_t tx_length = 2U << 20; // 2MB
39
+ size_t rx_length = 2U << 20; // 2MB
40
+ cmt_buf_init(me->tx, tx_length, malloc(tx_length));
41
+ cmt_buf_init(me->rx, rx_length, malloc(rx_length));
42
+
43
+ if (!me->tx->begin || !me->rx->begin) {
44
+ free(me->tx->begin);
45
+ free(me->rx->begin);
46
+ return -ENOMEM;
47
+ }
48
+
49
+ char *inputs = getenv("CMT_INPUTS");
50
+ if (inputs) {
51
+ cmt_buf_init(&me->inputs_left, strlen(inputs), inputs);
52
+ } else {
53
+ cmt_buf_init(&me->inputs_left, 0, "");
54
+ }
55
+
56
+ // in case the user writes something before loading any input
57
+ strcpy(me->input_filename, "none");
58
+ strcpy(me->input_fileext, ".bin");
59
+
60
+ me->input_seq = 0;
61
+ me->output_seq = 0;
62
+ me->report_seq = 0;
63
+ me->exception_seq = 0;
64
+ me->gio_seq = 0;
65
+
66
+ return 0;
67
+ }
68
+
69
+ void cmt_io_fini(cmt_io_driver_t *_me) {
70
+ if (!_me) {
71
+ return;
72
+ }
73
+
74
+ if (open_count == 0) {
75
+ return;
76
+ }
77
+
78
+ open_count--;
79
+ cmt_io_driver_mock_t *me = &_me->mock;
80
+
81
+ free(me->tx->begin);
82
+ free(me->rx->begin);
83
+
84
+ memset(_me, 0, sizeof(*_me));
85
+ }
86
+
87
+ cmt_buf_t cmt_io_get_tx(cmt_io_driver_t *me) {
88
+ cmt_buf_t empty = {NULL, NULL};
89
+ if (!me) {
90
+ return empty;
91
+ }
92
+ return *me->mock.tx;
93
+ }
94
+
95
+ cmt_buf_t cmt_io_get_rx(cmt_io_driver_t *me) {
96
+ cmt_buf_t empty = {NULL, NULL};
97
+ if (!me) {
98
+ return empty;
99
+ }
100
+ return *me->mock.rx;
101
+ }
102
+
103
+ static int load_next_input(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
104
+ cmt_buf_t current_input;
105
+ char filepath[128] = {0};
106
+ if (!cmt_buf_split_by_comma(&current_input, &me->inputs_left)) {
107
+ return -EINVAL;
108
+ }
109
+ // NOLINTNEXTLINE(cert-err34-c,clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
110
+ if (sscanf((char *) current_input.begin, "%d:%127[^,]", &me->input_type, filepath) != 2) {
111
+ return -EINVAL;
112
+ }
113
+
114
+ size_t file_length = 0;
115
+ int rc = cmt_util_read_whole_file(filepath, cmt_buf_length(me->rx), me->rx->begin, &file_length);
116
+ if (rc) {
117
+ if (cmt_util_debug_enabled()) {
118
+ (void) fprintf(stderr, "failed to load \"%s\". %s\n", filepath, strerror(-rc));
119
+ }
120
+ return rc;
121
+ }
122
+ // NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
123
+ if (sscanf(filepath, " %127[^.]%15s", me->input_filename, me->input_fileext) != 2) {
124
+ if (cmt_util_debug_enabled()) {
125
+ (void) fprintf(stderr, "failed to parse filename: \"%s\"\n", filepath);
126
+ }
127
+ return -EINVAL;
128
+ }
129
+ rr->reason = me->input_type;
130
+ rr->data = file_length;
131
+
132
+ me->output_seq = 0;
133
+ me->report_seq = 0;
134
+ me->exception_seq = 0;
135
+
136
+ if (cmt_util_debug_enabled()) {
137
+ (void) fprintf(stderr, "processing filename: \"%s\" (%lu), type: %d\n", filepath, file_length, me->input_type);
138
+ }
139
+ return 0;
140
+ }
141
+
142
+ static int store_output(cmt_io_driver_mock_t *me, const char *filepath, struct cmt_io_yield *rr) {
143
+ if (rr->data > cmt_buf_length(me->rx)) {
144
+ return -ENOBUFS;
145
+ }
146
+
147
+ int rc = cmt_util_write_whole_file(filepath, rr->data, me->tx->begin);
148
+ if (rc) {
149
+ (void) fprintf(stderr, "failed to store \"%s\". %s\n", filepath, strerror(-rc));
150
+ return rc;
151
+ }
152
+ if (cmt_util_debug_enabled()) {
153
+ (void) fprintf(stderr, "wrote filename: \"%s\" (%u)\n", filepath, rr->data);
154
+ }
155
+ return 0;
156
+ }
157
+
158
+ static int store_next_output(cmt_io_driver_mock_t *me, char *ns, int *seq, struct cmt_io_yield *rr) {
159
+ char filepath[128 + 32 + 8 + 16];
160
+ // NOLINTNEXTLINE(cert-err33-c, clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
161
+ snprintf(filepath, sizeof filepath, "%s.%s%d%s", me->input_filename, ns, (*seq)++, me->input_fileext);
162
+ return store_output(me, filepath, rr);
163
+ }
164
+
165
+ static int mock_progress(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
166
+ (void) me;
167
+ if (rr->cmd != HTIF_YIELD_CMD_AUTOMATIC) {
168
+ (void) fprintf(stderr, "Expected cmd to be AUTOMATIC\n");
169
+ return -EINVAL;
170
+ }
171
+ (void) fprintf(stderr, "Progress: %6.2f\n", (double) rr->data / 10);
172
+ return 0;
173
+ }
174
+
175
+ static int mock_rx_accepted(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
176
+ if (rr->cmd != HTIF_YIELD_CMD_MANUAL) {
177
+ (void) fprintf(stderr, "Expected cmd to be MANUAL\n");
178
+ return -EINVAL;
179
+ }
180
+ if (me->input_seq++) { // skip the first
181
+ char filepath[128 + 32 + 8 + 16];
182
+ // NOLINTNEXTLINE(cert-err33-c, clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
183
+ snprintf(filepath, sizeof filepath, "%s.outputs_root_hash%s", me->input_filename, me->input_fileext);
184
+ int rc = store_output(me, filepath, rr);
185
+ if (rc) {
186
+ return rc;
187
+ }
188
+ }
189
+ if (load_next_input(me, rr)) {
190
+ return -ENODATA;
191
+ }
192
+ return 0;
193
+ }
194
+
195
+ static int mock_rx_rejected(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
196
+ if (rr->cmd != HTIF_YIELD_CMD_MANUAL) {
197
+ (void) fprintf(stderr, "Expected cmd to be MANUAL\n");
198
+ return -EINVAL;
199
+ }
200
+ (void) fprintf(stderr, "%s:%d no revert for the mock implementation\n", __FILE__, __LINE__);
201
+ if (load_next_input(me, rr)) {
202
+ return -ENOSYS;
203
+ }
204
+ return 0;
205
+ }
206
+
207
+ static int mock_tx_output(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
208
+ if (rr->cmd != HTIF_YIELD_CMD_AUTOMATIC) {
209
+ (void) fprintf(stderr, "Expected cmd to be AUTOMATIC\n");
210
+ return -EINVAL;
211
+ }
212
+ return store_next_output(me, "output-", &me->output_seq, rr);
213
+ }
214
+
215
+ static int mock_tx_report(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
216
+ if (rr->cmd != HTIF_YIELD_CMD_AUTOMATIC) {
217
+ (void) fprintf(stderr, "Expected cmd to be AUTOMATIC\n");
218
+ return -EINVAL;
219
+ }
220
+ return store_next_output(me, "report-", &me->report_seq, rr);
221
+ }
222
+
223
+ static int mock_tx_exception(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
224
+ if (rr->cmd != HTIF_YIELD_CMD_MANUAL) {
225
+ (void) fprintf(stderr, "Expected cmd to be MANUAL\n");
226
+ return -EINVAL;
227
+ }
228
+ return store_next_output(me, "exception-", &me->exception_seq, rr);
229
+ }
230
+
231
+ static int mock_tx_gio(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
232
+ int rc = 0;
233
+ if (rr->cmd != HTIF_YIELD_CMD_MANUAL) {
234
+ (void) fprintf(stderr, "Expected cmd to be MANUAL\n");
235
+ return -EINVAL;
236
+ }
237
+
238
+ rc = store_next_output(me, "gio-", &me->gio_seq, rr);
239
+ if (rc) {
240
+ return rc;
241
+ }
242
+
243
+ rc = load_next_input(me, rr);
244
+ if (rc) {
245
+ return rc;
246
+ }
247
+ return 0;
248
+ }
249
+
250
+ /* These behaviours are defined by the cartesi-machine emulator */
251
+ static int cmt_io_yield_inner(cmt_io_driver_t *_me, struct cmt_io_yield *rr) {
252
+ cmt_io_driver_mock_t *me = &_me->mock;
253
+
254
+ if (rr->cmd == HTIF_YIELD_CMD_MANUAL) {
255
+ switch (rr->reason) {
256
+ case HTIF_YIELD_MANUAL_REASON_RX_ACCEPTED:
257
+ return mock_rx_accepted(me, rr);
258
+ case HTIF_YIELD_MANUAL_REASON_RX_REJECTED:
259
+ return mock_rx_rejected(me, rr);
260
+ case HTIF_YIELD_MANUAL_REASON_TX_EXCEPTION:
261
+ return mock_tx_exception(me, rr);
262
+ default:
263
+ return mock_tx_gio(me, rr);
264
+ }
265
+ } else if (rr->cmd == HTIF_YIELD_CMD_AUTOMATIC) {
266
+ switch (rr->reason) {
267
+ case HTIF_YIELD_AUTOMATIC_REASON_PROGRESS:
268
+ return mock_progress(me, rr);
269
+ case HTIF_YIELD_AUTOMATIC_REASON_TX_OUTPUT:
270
+ return mock_tx_output(me, rr);
271
+ case HTIF_YIELD_AUTOMATIC_REASON_TX_REPORT:
272
+ return mock_tx_report(me, rr);
273
+ default:
274
+ return -EINVAL;
275
+ }
276
+ } else {
277
+ return -EINVAL;
278
+ }
279
+
280
+ return 0;
281
+ }
282
+
283
+ /* emulate io.c:cmt_io_yield behavior (go and check it does if you change it) */
284
+ int cmt_io_yield(cmt_io_driver_t *_me, struct cmt_io_yield *rr) {
285
+ if (!_me) {
286
+ return -EINVAL;
287
+ }
288
+ if (!rr) {
289
+ return -EINVAL;
290
+ }
291
+
292
+ bool debug = cmt_util_debug_enabled();
293
+ if (debug) {
294
+ (void) fprintf(stderr,
295
+ "tohost {\n"
296
+ "\t.dev = %d,\n"
297
+ "\t.cmd = %d,\n"
298
+ "\t.reason = %d,\n"
299
+ "\t.data = %d,\n"
300
+ "};\n",
301
+ rr->dev, rr->cmd, rr->reason, rr->data);
302
+ }
303
+ int rc = cmt_io_yield_inner(_me, rr);
304
+ if (rc) {
305
+ return rc;
306
+ }
307
+
308
+ if (debug) {
309
+ (void) fprintf(stderr,
310
+ "fromhost {\n"
311
+ "\t.dev = %d,\n"
312
+ "\t.cmd = %d,\n"
313
+ "\t.reason = %d,\n"
314
+ "\t.data = %d,\n"
315
+ "};\n",
316
+ rr->dev, rr->cmd, rr->reason, rr->data);
317
+ }
318
+ return rc;
319
+ }
@@ -0,0 +1,164 @@
1
+ /* Copyright Cartesi and individual authors (see AUTHORS)
2
+ * SPDX-License-Identifier: Apache-2.0
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ #include "libcmt/io.h"
17
+ #include "libcmt/util.h"
18
+
19
+ #include <stdbool.h>
20
+ #include <stdio.h>
21
+ #include <stdlib.h>
22
+ #include <string.h>
23
+
24
+ #include <errno.h>
25
+ #include <fcntl.h>
26
+ #include <sys/ioctl.h>
27
+ #include <sys/mman.h>
28
+ #include <unistd.h>
29
+
30
+ #include <linux/cartesi/cmio.h>
31
+
32
+ int cmt_io_init(cmt_io_driver_t *_me) {
33
+ int rc = 0;
34
+
35
+ if (!_me) {
36
+ return -EINVAL;
37
+ }
38
+ cmt_io_driver_ioctl_t *me = &_me->ioctl;
39
+ me->fd = open("/dev/cmio", O_RDWR);
40
+
41
+ if (me->fd < 0) {
42
+ rc = -errno;
43
+ return rc;
44
+ }
45
+
46
+ struct cmio_setup setup;
47
+ if (ioctl(me->fd, IOCTL_CMIO_SETUP, &setup)) {
48
+ rc = -errno;
49
+ goto do_close;
50
+ }
51
+
52
+ void *tx = mmap((void *) setup.tx.data, setup.tx.length, PROT_READ | PROT_WRITE, MAP_SHARED, me->fd, 0);
53
+ if (tx == MAP_FAILED) {
54
+ rc = -errno;
55
+ goto do_close;
56
+ }
57
+
58
+ void *rx = mmap((void *) setup.rx.data, setup.rx.length, PROT_READ, MAP_SHARED, me->fd, 0);
59
+ if (rx == MAP_FAILED) {
60
+ rc = -errno;
61
+ goto do_unmap;
62
+ }
63
+
64
+ cmt_buf_init(me->tx, setup.tx.length, tx);
65
+ cmt_buf_init(me->rx, setup.rx.length, rx);
66
+ return 0;
67
+
68
+ do_unmap:
69
+ munmap(tx, setup.tx.length);
70
+ do_close:
71
+ close(me->fd);
72
+ return rc;
73
+ }
74
+
75
+ void cmt_io_fini(cmt_io_driver_t *_me) {
76
+ if (!_me) {
77
+ return;
78
+ }
79
+ cmt_io_driver_ioctl_t *me = &_me->ioctl;
80
+
81
+ munmap(me->tx->begin, cmt_buf_length(me->tx));
82
+ munmap(me->rx->begin, cmt_buf_length(me->rx));
83
+ close(me->fd);
84
+
85
+ memset(me, 0, sizeof(*me));
86
+ me->fd = -1;
87
+ }
88
+
89
+ cmt_buf_t cmt_io_get_tx(cmt_io_driver_t *me) {
90
+ const cmt_buf_t empty = {NULL, NULL};
91
+ if (!me) {
92
+ return empty;
93
+ }
94
+ return *me->ioctl.tx;
95
+ }
96
+
97
+ cmt_buf_t cmt_io_get_rx(cmt_io_driver_t *me) {
98
+ const cmt_buf_t empty = {NULL, NULL};
99
+ if (!me) {
100
+ return empty;
101
+ }
102
+ return *me->ioctl.rx;
103
+ }
104
+
105
+ static uint64_t pack(struct cmt_io_yield *rr) {
106
+ // clang-format off
107
+ return ((uint64_t) rr->dev << 56)
108
+ | ((uint64_t) rr->cmd << 56 >> 8)
109
+ | ((uint64_t) rr->reason << 48 >> 16)
110
+ | ((uint64_t) rr->data << 32 >> 32);
111
+ // clang-format on
112
+ }
113
+
114
+ static struct cmt_io_yield unpack(uint64_t x) {
115
+ // clang-format off
116
+ struct cmt_io_yield out = {
117
+ x >> 56,
118
+ x << 8 >> 56,
119
+ x << 16 >> 48,
120
+ x << 32 >> 32,
121
+ };
122
+ // clang-format on
123
+ return out;
124
+ }
125
+
126
+ /* io-mock.c:cmt_io_yield emulates this behavior (go and check it does if you change it) */
127
+ int cmt_io_yield(cmt_io_driver_t *_me, struct cmt_io_yield *rr) {
128
+ if (!_me) {
129
+ return -EINVAL;
130
+ }
131
+ if (!rr) {
132
+ return -EINVAL;
133
+ }
134
+ cmt_io_driver_ioctl_t *me = &_me->ioctl;
135
+
136
+ bool debug = cmt_util_debug_enabled();
137
+ if (debug) {
138
+ (void) fprintf(stderr,
139
+ "tohost {\n"
140
+ "\t.dev = %d,\n"
141
+ "\t.cmd = %d,\n"
142
+ "\t.reason = %d,\n"
143
+ "\t.data = %d,\n"
144
+ "};\n",
145
+ rr->dev, rr->cmd, rr->reason, rr->data);
146
+ }
147
+ uint64_t req = pack(rr);
148
+ if (ioctl(me->fd, IOCTL_CMIO_YIELD, &req)) {
149
+ return -errno;
150
+ }
151
+ *rr = unpack(req);
152
+
153
+ if (debug) {
154
+ (void) fprintf(stderr,
155
+ "fromhost {\n"
156
+ "\t.dev = %d,\n"
157
+ "\t.cmd = %d,\n"
158
+ "\t.reason = %d,\n"
159
+ "\t.data = %d,\n"
160
+ "};\n",
161
+ rr->dev, rr->cmd, rr->reason, rr->data);
162
+ }
163
+ return 0;
164
+ }
@@ -0,0 +1,156 @@
1
+ /* Copyright Cartesi and individual authors (see AUTHORS)
2
+ * SPDX-License-Identifier: Apache-2.0
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ #include "libcmt/keccak.h"
17
+ #include "libcmt/abi.h"
18
+
19
+ #include <string.h>
20
+
21
+ // Helper macros for stringification
22
+ #define TO_STRING_HELPER(X) #X
23
+ #define TO_STRING(X) TO_STRING_HELPER(X)
24
+
25
+ // Define loop unrolling depending on the compiler
26
+ #if defined(__clang__)
27
+ #define UNROLL_LOOP(n) _Pragma(TO_STRING(unroll(n)))
28
+ #elif defined(__GNUC__) && !defined(__clang__)
29
+ #define UNROLL_LOOP(n) _Pragma(TO_STRING(GCC unroll(n)))
30
+ #else
31
+ #define UNROLL_LOOP(n)
32
+ #endif
33
+
34
+ #define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
35
+
36
+ /** Initialize a keccak state
37
+ * @note don't port. use @ref cmt_keccak_init */
38
+ // clang-format off
39
+ #define CMT_KECCAK_INIT(STATE) \
40
+ { \
41
+ .st.q = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
42
+ .pt = 0, .rsiz = 200 - 2 * CMT_KECCAK_LENGTH, \
43
+ }
44
+
45
+ // clang-format on
46
+
47
+ static void keccakf(uint64_t st[25]) {
48
+ // clang-format off
49
+ const uint64_t keccakf_rndc[24] = {
50
+ 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, 0x000000000000808b,
51
+ 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, 0x0000000000000088,
52
+ 0x0000000080008009, 0x000000008000000a, 0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
53
+ 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
54
+ 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
55
+ };
56
+ const int keccakf_rotc[24] = { 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
57
+ 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 };
58
+ const int keccakf_piln[24] = { 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
59
+ 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 };
60
+ // clang-format on
61
+
62
+ #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
63
+ for (int i = 0; i < 25; i++) {
64
+ st[i] = __builtin_bswap64((uint64_t *) (st[i]));
65
+ }
66
+ #endif
67
+
68
+ for (int r = 0; r < 24; r++) {
69
+ uint64_t t = 0;
70
+ uint64_t bc[5];
71
+
72
+ // Theta
73
+ UNROLL_LOOP(5)
74
+ for (int i = 0; i < 5; i++) {
75
+ bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20];
76
+ }
77
+
78
+ UNROLL_LOOP(5)
79
+ for (int i = 0; i < 5; i++) {
80
+ t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1);
81
+ for (int j = 0; j < 25; j += 5) {
82
+ st[j + i] ^= t;
83
+ }
84
+ }
85
+
86
+ // Rho Pi
87
+ t = st[1];
88
+ UNROLL_LOOP(24)
89
+ for (int i = 0; i < 24; i++) {
90
+ int j = keccakf_piln[i];
91
+ bc[0] = st[j];
92
+ st[j] = ROTL64(t, keccakf_rotc[i]);
93
+ t = bc[0];
94
+ }
95
+
96
+ // Chi
97
+ UNROLL_LOOP(25)
98
+ for (int j = 0; j < 25; j += 5) {
99
+ for (int i = 0; i < 5; i++) {
100
+ bc[i] = st[j + i];
101
+ }
102
+ for (int i = 0; i < 5; i++) {
103
+ st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
104
+ }
105
+ }
106
+
107
+ // Iota
108
+ st[0] ^= keccakf_rndc[r];
109
+ }
110
+
111
+ #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
112
+ for (int i = 0; i < 25; i++) {
113
+ st[i] = __builtin_bswap64(st[i]);
114
+ }
115
+ #endif
116
+ }
117
+
118
+ void cmt_keccak_init(cmt_keccak_t *state) {
119
+ *state = (cmt_keccak_t) CMT_KECCAK_INIT(state);
120
+ }
121
+
122
+ void cmt_keccak_update(cmt_keccak_t *state, size_t n, const void *data) {
123
+ int j = state->pt;
124
+ for (size_t i = 0; i < n; i++) {
125
+ state->st.b[j++] ^= ((const uint8_t *) data)[i];
126
+ if (j >= state->rsiz) {
127
+ keccakf(state->st.q);
128
+ j = 0;
129
+ }
130
+ }
131
+ state->pt = j;
132
+ }
133
+
134
+ void cmt_keccak_final(cmt_keccak_t *state, void *md) {
135
+ state->st.b[state->pt] ^= 0x01;
136
+ state->st.b[state->rsiz - 1] ^= 0x80;
137
+ keccakf(state->st.q);
138
+
139
+ for (int i = 0; i < CMT_KECCAK_LENGTH; i++) {
140
+ ((uint8_t *) md)[i] = state->st.b[i];
141
+ }
142
+ }
143
+
144
+ uint8_t *cmt_keccak_data(size_t length, const void *data, uint8_t md[CMT_KECCAK_LENGTH]) {
145
+ cmt_keccak_t c[1];
146
+ cmt_keccak_init(c);
147
+ cmt_keccak_update(c, length, data);
148
+ cmt_keccak_final(c, md);
149
+ return md;
150
+ }
151
+
152
+ uint32_t cmt_keccak_funsel(const char *decl) {
153
+ uint8_t md[32];
154
+ cmt_keccak_data(strlen(decl), decl, md);
155
+ return CMT_ABI_FUNSEL(md[0], md[1], md[2], md[3]);
156
+ }