Line data Source code
1 : /**
2 : * The MIT License (MIT)
3 : *
4 : * Copyright (c) 2021 RSK Labs Ltd
5 : *
6 : * Permission is hereby granted, free of charge, to any person obtaining a copy
7 : * of this software and associated documentation files (the "Software"), to
8 : * deal in the Software without restriction, including without limitation the
9 : * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 : * sell copies of the Software, and to permit persons to whom the Software is
11 : * furnished to do so, subject to the following conditions:
12 : *
13 : * The above copyright notice and this permission notice shall be included in
14 : * all copies or substantial portions of the Software.
15 : *
16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 : * IN THE SOFTWARE.
23 : */
24 :
25 : #include <string.h>
26 :
27 : #include "bc.h"
28 : #include "hal/log.h"
29 : #include "defs.h"
30 : #include "ints.h"
31 : #include "mem.h"
32 : #include "srlp.h"
33 : #include "memutil.h"
34 :
35 : #include "bc_block.h"
36 : #include "bc_blockutils.h"
37 : #include "bc_ancestor.h"
38 : #include "bc_err.h"
39 : #include "bc_hash.h"
40 : #include "bc_mm.h"
41 : #include "bc_state.h"
42 : #include "util.h"
43 :
44 : // We'll be asking for block header chunks of at most this size
45 : #define MAX_CHUNK_SIZE 80
46 :
47 : // Number of blocks to validate
48 : static uint32_t expected_blocks;
49 :
50 : // Count of validated blocks
51 : static uint32_t curr_block;
52 :
53 : // Expected OP for next message
54 : static uint8_t expected_state;
55 :
56 : // -----------------------------------------------------------------------
57 : // Update ancestor validations
58 : // -----------------------------------------------------------------------
59 :
60 : /*
61 : * Update ancestor prologue: call once we have the first block's hash.
62 : */
63 3 : static void bc_upd_ancestor_prologue() {
64 3 : if (HNEQ(block.block_hash, N_bc_state.ancestor_block) &&
65 2 : HNEQ(block.block_hash, N_bc_state.best_block)) {
66 0 : FAIL(ANCESTOR_TIP_MISMATCH);
67 : }
68 3 : }
69 :
70 : /*
71 : * State updates to perform when successfully updated ancestor.
72 : */
73 3 : static void bc_upd_ancestor_success() {
74 3 : NVM_WRITE(N_bc_state.ancestor_block, block.block_hash, HASH_SIZE);
75 3 : NVM_WRITE(N_bc_state.ancestor_receipt_root, block.receipt_root, HASH_SIZE);
76 3 : }
77 :
78 : // -----------------------------------------------------------------------
79 : // RLP parser callbacks
80 : // -----------------------------------------------------------------------
81 :
82 : /*
83 : * Block starts: nesting level must not exceed one.
84 : *
85 : * @arg[in] size: size of list payload in bytes
86 : */
87 93 : static void list_start(const uint16_t size) {
88 93 : ++block.depth;
89 93 : if (block.depth != 1) {
90 0 : FAIL(RLP_INVALID);
91 : }
92 :
93 93 : block.size = size;
94 93 : block.recv = 0;
95 93 : }
96 :
97 : /*
98 : * List finishes: we must be closing the top level list, and received
99 : * bytes must match block size. In addition, we must have seen the
100 : * expected number of fields.
101 : */
102 93 : static void list_end() {
103 93 : --block.depth;
104 93 : if (block.depth != 0 || block.size != block.recv) {
105 0 : FAIL(RLP_INVALID);
106 : }
107 :
108 : // Block can end at the BTC mm header or anywhere past it
109 93 : if (block.field < F_MM_HEADER) {
110 0 : FAIL(BLOCK_TOO_SHORT);
111 : }
112 93 : }
113 :
114 : /*
115 : * Block field starts: field must be inside top level list.
116 : *
117 : * @arg[in] field size in bytes
118 : */
119 1674 : static void str_start(const uint16_t size) {
120 1674 : if (block.depth != 1) {
121 0 : FAIL(RLP_INVALID);
122 : }
123 :
124 1674 : block.wa_off = 0;
125 :
126 : // NOTE: This will return 1 even for a single byte "bad" string
127 : // where str[0] <= 0x7f (it should return 0). That's ok because
128 : // in that case we actually received a single byte. But we must
129 : // not add 1 to block.recv in str_chunk.
130 1674 : block.recv += guess_rlp_str_prefix_size(size);
131 :
132 : // Signal bad string
133 1674 : if (size == 1) {
134 190 : SET_FLAG(block.flags, BAD_STR);
135 : }
136 :
137 1674 : ++block.field;
138 :
139 1674 : if (block.field == F_PARENT_HASH && size != HASH_SIZE) {
140 0 : FAIL(PARENT_HASH_INVALID);
141 : }
142 :
143 1674 : if (block.field == F_RECEIPT_ROOT && size != HASH_SIZE) {
144 0 : FAIL(RECEIPT_ROOT_INVALID);
145 : }
146 :
147 1674 : if (SHOULD_COMPUTE_BLOCK_HASH) {
148 : // The starting str contributes to the block (and possibly mm) hash
149 : // - Good string: we can hash RLP prefix right now.
150 : // - Bad string: RLP prefix will depend on str contents.
151 1674 : if (!HAS_FLAG(block.flags, BAD_STR)) {
152 1484 : mm_hash_good_rlp_str_prefix(&block.block_ctx, size);
153 : }
154 : }
155 :
156 1674 : if (block.field == F_MM_HEADER && size != BTC_HEADER_SIZE) {
157 0 : FAIL(BTC_HEADER_INVALID);
158 : }
159 1674 : }
160 :
161 : /*
162 : * Block chunk arrived.
163 : *
164 : * @arg[in] chunk pointer to arrived chunk
165 : * @arg[in] size size in bytes of arrived chunk
166 : */
167 2325 : static void str_chunk(const uint8_t* chunk, const size_t size) {
168 : // Count chunk length as received bytes only if:
169 : // - Chunk doesn't belong to a bad string, or
170 : // - Bad string actually has RLP prefix
171 2325 : if (!HAS_FLAG(block.flags, BAD_STR) || HAS_RLP_PREFIX(chunk[0])) {
172 2135 : block.recv += size;
173 : }
174 :
175 2325 : if (block.field == F_PARENT_HASH) {
176 186 : WA_STORE(chunk, size);
177 : }
178 :
179 : // Store receipt only for last block
180 2325 : if (block.field == F_RECEIPT_ROOT && curr_block + 1 == expected_blocks) {
181 12 : WA_STORE(chunk, size);
182 : }
183 :
184 2325 : if (block.field == F_BLOCK_NUM) {
185 186 : WA_STORE(chunk, size);
186 : }
187 :
188 2325 : if (block.field == F_MM_HEADER) {
189 372 : WA_STORE(chunk, size);
190 : }
191 :
192 2325 : if (SHOULD_COMPUTE_BLOCK_HASH) {
193 : // Chunk corresponds to a bad str, so we couldn't hash its RLP prefix
194 : // until now, when str contents are available. Hash prefix now.
195 2325 : if (HAS_FLAG(block.flags, BAD_STR)) {
196 190 : mm_hash_bad_rlp_str_prefix(&block.block_ctx, chunk);
197 : }
198 :
199 : // And then hash the str chunk itself
200 2325 : KECCAK_UPDATE(&block.block_ctx, chunk, size);
201 : }
202 2325 : }
203 :
204 : /* Current block chunk finished */
205 1674 : static void str_end() {
206 1674 : if (block.field == F_PARENT_HASH) {
207 93 : HSTORE(block.parent_hash, block.wa_buf);
208 : }
209 :
210 : // Store receipt root only for last block
211 1674 : if (block.field == F_RECEIPT_ROOT && curr_block + 1 == expected_blocks) {
212 3 : HSTORE(block.receipt_root, block.wa_buf);
213 : }
214 :
215 : // Block number in wa_buf:
216 : // Store for computing mm_hash and determine network upgrade
217 1674 : if (block.field == F_BLOCK_NUM) {
218 93 : if (block.wa_off > sizeof(block.number)) {
219 0 : FAIL(BLOCK_NUM_INVALID);
220 : }
221 279 : VAR_BIGENDIAN_FROM(block.wa_buf, block.number, block.wa_off);
222 93 : SET_NETWORK_UPGRADE(block.number, &block.network_upgrade);
223 93 : if (block.network_upgrade == NU_ANCIENT) {
224 0 : FAIL(BLOCK_TOO_OLD);
225 : }
226 : }
227 :
228 : // Verify that we got valid mm_rlp_len in OP_UPD_ANCESTOR_HEADER_META
229 1674 : if (block.field == MM_HASH_LAST_FIELD) {
230 93 : if (block.recv != block.mm_rlp_len) {
231 0 : FAIL(MM_RLP_LEN_MISMATCH);
232 : }
233 : }
234 :
235 : // We have the complete merge mining header in wa_buf. We must:
236 : // - Finalize the block hash computation
237 : // - Signal the merge mining header was received
238 1674 : if (block.field == F_MM_HEADER) {
239 93 : KECCAK_FINAL(&block.block_ctx, block.block_hash);
240 93 : SET_FLAG(block.flags, MM_HEADER_RECV);
241 : }
242 :
243 : // Done with this chunk, clear BAD_STR flag if set
244 1674 : if (HAS_FLAG(block.flags, BAD_STR)) {
245 190 : CLR_FLAG(block.flags, BAD_STR);
246 : }
247 1674 : }
248 :
249 : static const rlp_callbacks_t callbacks = {
250 : str_start,
251 : str_chunk,
252 : str_end,
253 : list_start,
254 : list_end,
255 : };
256 :
257 : // -----------------------------------------------------------------------
258 : // Blockchain update ancestor implementation
259 : // -----------------------------------------------------------------------
260 :
261 : /*
262 : * Initialize Blockchain update ancestor protocol state.
263 : */
264 270 : void bc_init_upd_ancestor() {
265 270 : expected_blocks = 0;
266 270 : curr_block = 0;
267 270 : expected_state = OP_UPD_ANCESTOR_INIT;
268 270 : }
269 :
270 : /*
271 : * Update blockchain ancestor.
272 : *
273 : * @arg[in] rx number of received bytes from the Host
274 : * @ret number of transmited bytes to the host
275 : */
276 840 : unsigned int bc_upd_ancestor(volatile unsigned int rx) {
277 840 : uint8_t op = APDU_OP();
278 :
279 : // Check we are getting expected OP
280 840 : if (op != OP_UPD_ANCESTOR_INIT && op != expected_state) {
281 0 : FAIL(PROT_INVALID);
282 : }
283 :
284 : // Check we are getting the expected amount of data
285 840 : if (op == OP_UPD_ANCESTOR_INIT && APDU_DATA_SIZE(rx) != sizeof(uint32_t)) {
286 0 : FAIL(PROT_INVALID);
287 : }
288 840 : if (op == OP_UPD_ANCESTOR_HEADER_META &&
289 93 : APDU_DATA_SIZE(rx) != sizeof(block.mm_rlp_len)) {
290 0 : FAIL(PROT_INVALID);
291 : }
292 840 : if (op == OP_UPD_ANCESTOR_HEADER_CHUNK) {
293 93 : uint16_t expected_txlen =
294 744 : block.size > 0 ? MIN(block.size - block.recv, MAX_CHUNK_SIZE)
295 : : MAX_CHUNK_SIZE;
296 744 : if (APDU_DATA_SIZE(rx) != expected_txlen) {
297 0 : FAIL(PROT_INVALID);
298 : }
299 : }
300 :
301 : // -------------------------------------------------------------------
302 : // OP_INIT
303 : // -------------------------------------------------------------------
304 840 : if (op == OP_UPD_ANCESTOR_INIT) {
305 3 : expected_state = OP_UPD_ANCESTOR_HEADER_META;
306 :
307 3 : memset(aux_bc_st.prev_parent_hash, 0, HASH_SIZE);
308 :
309 3 : curr_block = 0;
310 15 : BIGENDIAN_FROM(APDU_DATA_PTR, expected_blocks);
311 3 : if (expected_blocks == 0) {
312 0 : FAIL(PROT_INVALID);
313 : }
314 :
315 3 : SET_APDU_OP(OP_UPD_ANCESTOR_HEADER_META);
316 3 : return TX_NO_DATA();
317 : }
318 :
319 : // -------------------------------------------------------------------
320 : // OP_HEADER_META
321 : // -------------------------------------------------------------------
322 837 : if (op == OP_UPD_ANCESTOR_HEADER_META) {
323 93 : LOG("---- Block %u of %u\n", curr_block + 1, expected_blocks);
324 :
325 : // Clear block data
326 93 : memset(&block, 0, sizeof(block));
327 93 : rlp_start(&callbacks);
328 :
329 : // Read the RLP payload length
330 279 : BIGENDIAN_FROM(APDU_DATA_PTR, block.mm_rlp_len);
331 :
332 : // Block hash computation: encode and hash payload len
333 :
334 : // Sanity check: make sure given mm_rlp_len plus BTC_HEADER_RLP_LEN does
335 : // not overflow
336 93 : if ((uint16_t)(block.mm_rlp_len + BTC_HEADER_RLP_LEN) <
337 : block.mm_rlp_len) {
338 0 : LOG("Given MM RLP list length too large, would overflow: %u\n",
339 0 : block.mm_rlp_len);
340 0 : FAIL(PROT_INVALID);
341 : }
342 :
343 93 : KECCAK_INIT(&block.block_ctx);
344 93 : mm_hash_rlp_list_prefix(&block.block_ctx,
345 93 : block.mm_rlp_len + BTC_HEADER_RLP_LEN);
346 :
347 : // Now waiting for block data
348 93 : expected_state = OP_UPD_ANCESTOR_HEADER_CHUNK;
349 93 : SET_APDU_OP(OP_UPD_ANCESTOR_HEADER_CHUNK);
350 93 : SET_APDU_TXLEN(MAX_CHUNK_SIZE);
351 :
352 93 : return TX_FOR_DATA_SIZE(1);
353 : }
354 :
355 : // -------------------------------------------------------------------
356 : // OP_HEADER_CHUNK
357 : // -------------------------------------------------------------------
358 744 : if (op == OP_UPD_ANCESTOR_HEADER_CHUNK) {
359 744 : if (rlp_consume(APDU_DATA_PTR, APDU_DATA_SIZE(rx)) < 0) {
360 0 : FAIL(RLP_INVALID);
361 : }
362 :
363 : // We have received the whole BTC merge mining header.
364 : // So we have the block hash. Since we aren't validating
365 : // blocks here, after validating parent chaining we can
366 : // ask for next block or leave.
367 744 : if (HAS_FLAG(block.flags, MM_HEADER_RECV)) {
368 :
369 93 : LOG_HEX("Block hash", block.block_hash, HASH_SIZE);
370 93 : LOG_HEX("Parent hash", block.parent_hash, HASH_SIZE);
371 :
372 : // First block: perform update ancestor prologue
373 : // Otherwise: verify block chains to parent
374 93 : if (curr_block == 0) {
375 3 : bc_upd_ancestor_prologue();
376 90 : } else if (HNEQ(aux_bc_st.prev_parent_hash, block.block_hash)) {
377 0 : FAIL(CHAIN_MISMATCH);
378 : }
379 : // Store parent hash to validate chaining for next block
380 : // (next block hash must match this block's parent hash)
381 93 : HSTORE(aux_bc_st.prev_parent_hash, block.parent_hash);
382 :
383 93 : ++curr_block;
384 :
385 : // More blocks? Ask for next block metadata
386 93 : if (curr_block < expected_blocks) {
387 90 : expected_state = OP_UPD_ANCESTOR_HEADER_META;
388 90 : SET_APDU_OP(OP_UPD_ANCESTOR_HEADER_META);
389 90 : return TX_NO_DATA();
390 : }
391 :
392 : // Blocks exhausted? Leave
393 3 : bc_upd_ancestor_success();
394 3 : expected_state = OP_UPD_ANCESTOR_INIT;
395 3 : SET_APDU_OP(OP_UPD_ANCESTOR_SUCCESS);
396 3 : return TX_NO_DATA();
397 : }
398 :
399 : // Current block not fully consumed? Ask for next chunk
400 651 : if (block.recv < block.size) {
401 651 : SET_APDU_OP(OP_UPD_ANCESTOR_HEADER_CHUNK);
402 651 : SET_APDU_TXLEN(MIN(block.size - block.recv, MAX_CHUNK_SIZE));
403 651 : return TX_FOR_DATA_SIZE(1);
404 : }
405 :
406 : // Reached end of block and haven't seen BTC mm header? That's bad!
407 0 : FAIL(RLP_INVALID);
408 : }
409 :
410 : // You shouldn't be here
411 0 : FAIL(PROT_INVALID);
412 : return 0;
413 : }
|