cryptnox-sdk-esp32 1.0.0
ESP32 SDK for Cryptnox Hardware Wallet
Loading...
Searching...
No Matches
keccak256.cpp
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: LGPL-3.0-or-later
3 * Copyright (c) 2026 Cryptnox SA
4 */
5
6#include "keccak256.h"
7#include <string.h>
8
9#define KECCAK_ROUNDS 24U
10#define KECCAK_RATE 136U /* 1088 / 8 bytes — rate for 256-bit output */
11#define KECCAK_STATE_LANE 25U /* 5×5 uint64_t lanes */
12
13static const uint64_t kRC[KECCAK_ROUNDS] = {
14 0x0000000000000001ULL, 0x0000000000008082ULL,
15 0x800000000000808AULL, 0x8000000080008000ULL,
16 0x000000000000808BULL, 0x0000000080000001ULL,
17 0x8000000080008081ULL, 0x8000000000008009ULL,
18 0x000000000000008AULL, 0x0000000000000088ULL,
19 0x0000000080008009ULL, 0x000000008000000AULL,
20 0x000000008000808BULL, 0x800000000000008BULL,
21 0x8000000000008089ULL, 0x8000000000008003ULL,
22 0x8000000000008002ULL, 0x8000000000000080ULL,
23 0x000000000000800AULL, 0x800000008000000AULL,
24 0x8000000080008081ULL, 0x8000000000008080ULL,
25 0x0000000080000001ULL, 0x8000000080008008ULL,
26};
27
28/* Rho rotation offsets for lane [x + 5*y], derived from the Keccak spec. */
29static const uint8_t kRHO[KECCAK_STATE_LANE] = {
30 0, 1, 62, 28, 27, /* y=0 */
31 36, 44, 6, 55, 20, /* y=1 */
32 3, 10, 43, 25, 39, /* y=2 */
33 41, 45, 15, 21, 8, /* y=3 */
34 18, 2, 61, 56, 14 /* y=4 */
35};
36
37static uint64_t rot64(uint64_t x, uint8_t n)
38{
39 return (n == 0U) ? x : ((x << n) | (x >> (64U - n)));
40}
41
42static void keccak_f1600(uint64_t st[KECCAK_STATE_LANE])
43{
44 uint64_t C[5], D[5], B[KECCAK_STATE_LANE];
45 unsigned int round, x, y;
46
47 for (round = 0U; round < KECCAK_ROUNDS; round++) {
48 /* Theta */
49 for (x = 0U; x < 5U; x++) {
50 C[x] = st[x] ^ st[x + 5U] ^ st[x + 10U] ^ st[x + 15U] ^ st[x + 20U];
51 }
52 for (x = 0U; x < 5U; x++) {
53 D[x] = C[(x + 4U) % 5U] ^ rot64(C[(x + 1U) % 5U], 1U);
54 }
55 for (x = 0U; x < 5U; x++) {
56 for (y = 0U; y < 5U; y++) {
57 st[x + 5U * y] ^= D[x];
58 }
59 }
60
61 /* Rho + Pi: B[dst] = ROT(st[src], rho[src]) */
62 for (x = 0U; x < 5U; x++) {
63 for (y = 0U; y < 5U; y++) {
64 unsigned int src = x + 5U * y;
65 unsigned int dst_x = y;
66 unsigned int dst_y = (2U * x + 3U * y) % 5U;
67 B[dst_x + 5U * dst_y] = rot64(st[src], kRHO[src]);
68 }
69 }
70
71 /* Chi */
72 for (x = 0U; x < 5U; x++) {
73 for (y = 0U; y < 5U; y++) {
74 st[x + 5U * y] = B[x + 5U * y] ^
75 ((~B[(x + 1U) % 5U + 5U * y]) &
76 B[(x + 2U) % 5U + 5U * y]);
77 }
78 }
79
80 /* Iota */
81 st[0] ^= kRC[round];
82 }
83}
84
85void keccak256(const uint8_t *input, size_t length, uint8_t digest[32])
86{
87 uint64_t state[KECCAK_STATE_LANE];
88 uint8_t *sb = (uint8_t *)state;
89 size_t offset = 0U;
90 size_t i;
91
92 (void)memset(state, 0, sizeof(state));
93
94 /* Absorb full blocks */
95 while ((length - offset) >= KECCAK_RATE) {
96 for (i = 0U; i < KECCAK_RATE; i++) {
97 sb[i] ^= input[offset + i];
98 }
99 keccak_f1600(state);
100 offset += KECCAK_RATE;
101 }
102
103 /* Absorb remaining bytes */
104 size_t rem = length - offset;
105 for (i = 0U; i < rem; i++) {
106 sb[i] ^= input[offset + i];
107 }
108
109 /* Pad: 0x01 for Ethereum Keccak (pre-NIST), 0x80 at end of rate block */
110 sb[rem] ^= 0x01U;
111 sb[KECCAK_RATE - 1U] ^= 0x80U;
112
113 keccak_f1600(state);
114
115 /* Squeeze first 32 bytes */
116 (void)memcpy(digest, sb, 32U);
117}
#define KECCAK_STATE_LANE
Definition keccak256.cpp:11
static void keccak_f1600(uint64_t st[KECCAK_STATE_LANE])
Definition keccak256.cpp:42
static const uint64_t kRC[KECCAK_ROUNDS]
Definition keccak256.cpp:13
static uint64_t rot64(uint64_t x, uint8_t n)
Definition keccak256.cpp:37
static const uint8_t kRHO[KECCAK_STATE_LANE]
Definition keccak256.cpp:29
#define KECCAK_ROUNDS
Definition keccak256.cpp:9
void keccak256(const uint8_t *input, size_t length, uint8_t digest[32])
Definition keccak256.cpp:85
#define KECCAK_RATE
Definition keccak256.cpp:10