Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
aes128.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Khashayar], commit: 21476601b111f046f023474465598843e4cfd8ac}
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#include "aes128.hpp"
8
11#include "memory.h"
12#include <array>
13#include <cstddef>
14#include <cstdint>
15
16namespace {
17
18static constexpr uint8_t round_constants[11] = { 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
19
20inline void add_round_key(uint8_t* state, const uint8_t* round_key, const size_t round)
21{
22 for (size_t i = 0; i < 16; i += 4) {
23 for (size_t j = 0; j < 4; ++j) {
24 state[i + j] ^= round_key[(round * 16U) + i + j];
25 }
26 }
27}
28
29inline void xor_with_iv(uint8_t* state, const uint8_t* iv)
30{
31 for (size_t i = 0; i < 16; ++i) {
32 state[i] ^= iv[i];
33 }
34}
35
36void sub_bytes(uint8_t* input)
37{
38 uint8_t i, j;
39 for (i = 0; i < 4; ++i) {
40 for (j = 0; j < 4; ++j) {
41 input[j * 4 + i] = bb::crypto::aes128_sbox[input[j * 4 + i]];
42 }
43 }
44}
45
46void inverse_sub_bytes(uint8_t* input)
47{
48 for (size_t i = 0; i < 4; ++i) {
49 for (size_t j = 0; j < 4; ++j) {
50 input[j * 4 + i] = bb::crypto::aes128_sbox_inverse[input[j * 4 + i]];
51 }
52 }
53}
54
55void shift_rows(uint8_t* input)
56{
57 uint8_t temp;
58
59 temp = input[0 * 4 + 1];
60 input[0 * 4 + 1] = input[1 * 4 + 1];
61 input[1 * 4 + 1] = input[2 * 4 + 1];
62 input[2 * 4 + 1] = input[3 * 4 + 1];
63 input[3 * 4 + 1] = temp;
64
65 temp = input[0 * 4 + 2];
66 input[0 * 4 + 2] = input[2 * 4 + 2];
67 input[2 * 4 + 2] = temp;
68
69 temp = input[1 * 4 + 2];
70 input[1 * 4 + 2] = input[3 * 4 + 2];
71 input[3 * 4 + 2] = temp;
72
73 temp = input[0 * 4 + 3];
74 input[0 * 4 + 3] = input[3 * 4 + 3];
75 input[3 * 4 + 3] = input[2 * 4 + 3];
76 input[2 * 4 + 3] = input[1 * 4 + 3];
77 input[1 * 4 + 3] = temp;
78}
79
80static void inverse_shift_rows(uint8_t* input)
81{
82 uint8_t temp;
83
84 temp = input[3 * 4 + 1];
85 input[3 * 4 + 1] = input[2 * 4 + 1];
86 input[2 * 4 + 1] = input[1 * 4 + 1];
87 input[1 * 4 + 1] = input[0 * 4 + 1];
88 input[0 * 4 + 1] = temp;
89
90 temp = input[0 * 4 + 2];
91 input[0 * 4 + 2] = input[2 * 4 + 2];
92 input[2 * 4 + 2] = temp;
93
94 temp = input[1 * 4 + 2];
95 input[1 * 4 + 2] = input[3 * 4 + 2];
96 input[3 * 4 + 2] = temp;
97
98 temp = input[0 * 4 + 3];
99 input[0 * 4 + 3] = input[1 * 4 + 3];
100 input[1 * 4 + 3] = input[2 * 4 + 3];
101 input[2 * 4 + 3] = input[3 * 4 + 3];
102 input[3 * 4 + 3] = temp;
103}
104
105uint8_t xtime(const uint8_t x)
106{
107 return static_cast<uint8_t>((x << 1) ^ (((x >> 7) & 1) * 0x1b));
108}
109
110uint8_t gf2_8_mul(const uint8_t x, const uint8_t y)
111{
112 const uint8_t t0 = (uint8_t)((y & (uint8_t)1) * x);
113 const uint8_t t1 = (uint8_t)(((y >> (uint8_t)1) & (uint8_t)1) * xtime(x));
114 const uint8_t t2 = (uint8_t)(((y >> (uint8_t)2) & (uint8_t)1) * xtime(xtime(x)));
115 const uint8_t t3 = (uint8_t)(((y >> (uint8_t)3) & (uint8_t)1) * xtime(xtime(xtime(x))));
116 const uint8_t t4 = (uint8_t)(((y >> (uint8_t)4) & (uint8_t)1) * xtime(xtime(xtime(xtime(x)))));
117
118 uint8_t out = t0 ^ t1 ^ t2 ^ t3 ^ t4;
119 return out;
120}
121
122void mix_columns(uint8_t* input)
123{
124 for (uint8_t i = 0; i < 4; ++i) {
125 uint8_t t = input[i * 4 + 0];
126 uint8_t Tmp = input[i * 4 + 0] ^ input[i * 4 + 1] ^ input[i * 4 + 2] ^ input[i * 4 + 3];
127 uint8_t Tm = input[i * 4 + 0] ^ input[i * 4 + 1];
128 Tm = xtime(Tm);
129 input[i * 4 + 0] ^= Tm ^ Tmp;
130 Tm = input[i * 4 + 1] ^ input[i * 4 + 2];
131 Tm = xtime(Tm);
132 input[i * 4 + 1] ^= Tm ^ Tmp;
133 Tm = input[i * 4 + 2] ^ input[i * 4 + 3];
134 Tm = xtime(Tm);
135 input[i * 4 + 2] ^= Tm ^ Tmp;
136 Tm = input[i * 4 + 3] ^ t;
137 Tm = xtime(Tm);
138 input[i * 4 + 3] ^= Tm ^ Tmp;
139 }
140}
141
142void inverse_mix_columns(uint8_t* input)
143{
144 for (uint8_t i = 0; i < 4; ++i) {
145 uint8_t a = input[i * 4 + 0];
146 uint8_t b = input[i * 4 + 1];
147 uint8_t c = input[i * 4 + 2];
148 uint8_t d = input[i * 4 + 3];
149
150 input[i * 4 + 0] = gf2_8_mul(a, 0x0e) ^ gf2_8_mul(b, 0x0b) ^ gf2_8_mul(c, 0x0d) ^ gf2_8_mul(d, 0x09);
151 input[i * 4 + 1] = gf2_8_mul(a, 0x09) ^ gf2_8_mul(b, 0x0e) ^ gf2_8_mul(c, 0x0b) ^ gf2_8_mul(d, 0x0d);
152 input[i * 4 + 2] = gf2_8_mul(a, 0x0d) ^ gf2_8_mul(b, 0x09) ^ gf2_8_mul(c, 0x0e) ^ gf2_8_mul(d, 0x0b);
153 input[i * 4 + 3] = gf2_8_mul(a, 0x0b) ^ gf2_8_mul(b, 0x0d) ^ gf2_8_mul(c, 0x09) ^ gf2_8_mul(d, 0x0e);
154 }
155}
156} // namespace
157
158namespace bb::crypto {
159
160void aes128_expand_key(const uint8_t* key, uint8_t* round_key)
161{
162 uint8_t temp[4]{};
163
164 for (size_t i = 0; i < 16; i += 4) {
165 round_key[i] = key[i];
166 round_key[i + 1] = key[i + 1];
167 round_key[i + 2] = key[i + 2];
168 round_key[i + 3] = key[i + 3];
169 }
170
171 for (size_t i = 4; i < 44; ++i) {
172 size_t k = (i - 1) * 4;
173 temp[0] = round_key[k];
174 temp[1] = round_key[k + 1];
175 temp[2] = round_key[k + 2];
176 temp[3] = round_key[k + 3];
177
178 if ((i & 0x03) == 0) {
179 const uint8_t t = temp[0];
180 temp[0] = temp[1];
181 temp[1] = temp[2];
182 temp[2] = temp[3];
183 temp[3] = t;
184
185 temp[0] = aes128_sbox[temp[0]];
186 temp[1] = aes128_sbox[temp[1]];
187 temp[2] = aes128_sbox[temp[2]];
188 temp[3] = aes128_sbox[temp[3]];
189
190 temp[0] = temp[0] ^ round_constants[i >> 2];
191 }
192 size_t j = i * 4;
193 k = (i - 4) * 4;
194 round_key[j] = round_key[k] ^ temp[0];
195 round_key[j + 1] = round_key[k + 1] ^ temp[1];
196 round_key[j + 2] = round_key[k + 2] ^ temp[2];
197 round_key[j + 3] = round_key[k + 3] ^ temp[3];
198 }
199 secure_erase_bytes(temp, sizeof(temp));
200}
201
202void aes128_inverse_cipher(uint8_t* input, const uint8_t* round_key)
203{
204
205 add_round_key(input, round_key, 10);
206
207 for (size_t round = 9; round > 0; --round) {
208 inverse_shift_rows(input);
209 inverse_sub_bytes(input);
210 add_round_key(input, round_key, round);
211 inverse_mix_columns(input);
212 }
213 inverse_shift_rows(input);
214 inverse_sub_bytes(input);
215 add_round_key(input, round_key, 0);
216}
217
218void aes128_cipher(uint8_t* state, const uint8_t* round_key)
219{
220 add_round_key(state, round_key, 0);
221
222 for (uint8_t round = 1; round < 10; ++round) {
223 sub_bytes(state);
224 shift_rows(state);
225 mix_columns(state);
226 add_round_key(state, round_key, round);
227 }
228
229 sub_bytes(state);
230 shift_rows(state);
231 add_round_key(state, round_key, 10);
232}
233
234void aes128_encrypt_buffer_cbc(uint8_t* buffer, uint8_t* iv, const uint8_t* key, const size_t length)
235{
236 BB_ASSERT(length % 16 == 0, "aes128_encrypt_buffer_cbc: length must be a multiple of 16");
237
238 uint8_t round_key[176];
239 aes128_expand_key(key, round_key);
240
241 uint8_t block_state[16]{};
242
243 const size_t num_blocks = (length / 16);
244
245 for (size_t i = 0; i < num_blocks; ++i) {
246 memcpy((void*)block_state, (void*)(buffer + (i * 16)), 16);
247 xor_with_iv(block_state, iv);
248
249 aes128_cipher(block_state, round_key);
250
251 memcpy((void*)(buffer + (i * 16)), (void*)block_state, 16);
252 memcpy((void*)iv, (void*)block_state, 16);
253 }
254 secure_erase_bytes(round_key, sizeof(round_key));
255}
256
257void aes128_decrypt_buffer_cbc(uint8_t* buffer, uint8_t* iv, const uint8_t* key, const size_t length)
258{
259 BB_ASSERT(length % 16 == 0, "aes128_decrypt_buffer_cbc: length must be a multiple of 16");
260
261 uint8_t round_key[176];
262 aes128_expand_key(key, round_key);
263 uint8_t block_state[16]{};
264 const size_t num_blocks = (length / 16);
265
266 uint8_t next_iv[16]{};
267 for (size_t i = 0; i < num_blocks; ++i) {
268 memcpy((void*)block_state, (void*)(buffer + (i * 16)), 16);
269 memcpy((void*)next_iv, (void*)block_state, 16);
270 aes128_inverse_cipher(block_state, round_key);
271 xor_with_iv(block_state, iv);
272 memcpy((void*)(buffer + (i * 16)), (void*)block_state, 16);
273 memcpy((void*)iv, (void*)next_iv, 16);
274 }
275 secure_erase_bytes(round_key, sizeof(round_key));
276}
277
278} // namespace bb::crypto
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
FF a
FF b
std::unique_ptr< uint8_t[]> buffer
Definition engine.cpp:60
constexpr uint32_t round_constants[64]
void aes128_inverse_cipher(uint8_t *input, const uint8_t *round_key)
Definition aes128.cpp:202
void aes128_decrypt_buffer_cbc(uint8_t *buffer, uint8_t *iv, const uint8_t *key, const size_t length)
Definition aes128.cpp:257
void aes128_expand_key(const uint8_t *key, uint8_t *round_key)
Definition aes128.cpp:160
void aes128_cipher(uint8_t *state, const uint8_t *round_key)
Definition aes128.cpp:218
void aes128_encrypt_buffer_cbc(uint8_t *buffer, uint8_t *iv, const uint8_t *key, const size_t length)
Definition aes128.cpp:234
void secure_erase_bytes(void *ptr, size_t size)
Definition hmac.hpp:18
void sub_bytes(Builder *ctx, state_span< Builder > state_pairs)
Definition aes128.cpp:305
void shift_rows(state_span< Builder > state)
The SHIFTROW() operation as in FIPS 197, Section 5.1.2.
Definition aes128.cpp:213
void add_round_key(state_span< Builder > sparse_state, key_span< Builder > sparse_round_key, size_t round)
Definition aes128.cpp:313
void xor_with_iv(state_span< Builder > state, block_span< Builder > iv)
Definition aes128.cpp:323