LCOV - code coverage report
Current view: top level - powhsm/src - bc_state.c (source / functions) Hit Total Coverage
Test: powHSM firmware Lines: 66 80 82.5 %
Date: 2025-07-10 13:49:13 Functions: 7 8 87.5 %

          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 <stdbool.h>
      26             : #include <string.h>
      27             : 
      28             : #include "runtime.h"
      29             : #include "defs.h"
      30             : #include "err.h"
      31             : #include "hal/log.h"
      32             : #include "nvm.h"
      33             : #include "memutil.h"
      34             : 
      35             : #include "bc_state.h"
      36             : #include "bc_err.h"
      37             : 
      38             : #include "mem.h"
      39             : 
      40             : // -----------------------------------------------------------------------
      41             : // Blockchain state initialization
      42             : // -----------------------------------------------------------------------
      43             : 
      44             : // Here we take it from an external definition (see Makefile for details)
      45             : #if (defined(HSM_PLATFORM_LEDGER) || defined(HSM_PLATFORM_SGX)) && \
      46             :     defined(PARAM_INITIAL_BLOCK_HASH)
      47             : static const uint8_t INITIAL_BLOCK_HASH[] = PARAM_INITIAL_BLOCK_HASH;
      48             : #elif defined(HSM_PLATFORM_X86)
      49             : uint8_t INITIAL_BLOCK_HASH[HASH_LENGTH];
      50             : #else
      51             : #error "Initial block hash not defined!"
      52             : #endif
      53             : 
      54             : /*
      55             :  * Initialize blockchain state.
      56             :  */
      57           2 : void bc_init_state() {
      58           2 :     if (!N_bc_state.initialized) {
      59           1 :         NVM_RESET(&N_bc_state, sizeof(N_bc_state));
      60           1 :         NVM_WRITE(N_bc_state.best_block, INITIAL_BLOCK_HASH, HASH_SIZE);
      61           1 :         NVM_WRITE(N_bc_state.newest_valid_block, INITIAL_BLOCK_HASH, HASH_SIZE);
      62             : 
      63           1 :         uint8_t t = 1;
      64           1 :         NVM_WRITE(&N_bc_state.initialized, &t, sizeof(t));
      65             :     }
      66             : 
      67           2 :     explicit_bzero(&bc_st_updating, sizeof(bc_st_updating));
      68           2 :     if (N_bc_state_updating_backup.valid) {
      69           0 :         uint8_t f = 0;
      70           0 :         NVM_WRITE(&N_bc_state_updating_backup.valid, &f, sizeof(f));
      71           0 :         SAFE_MEMMOVE(&bc_st_updating,
      72             :                      sizeof(bc_st_updating),
      73             :                      MEMMOVE_ZERO_OFFSET,
      74             :                      &N_bc_state_updating_backup.data,
      75             :                      sizeof(N_bc_state_updating_backup.data),
      76             :                      MEMMOVE_ZERO_OFFSET,
      77             :                      sizeof(N_bc_state_updating_backup.data),
      78             :                      { return; });
      79             :     }
      80             : }
      81             : 
      82             : /**
      83             :  * Backup the current partial advance blockchain state
      84             :  * to NVM
      85             :  */
      86           0 : void bc_backup_partial_state() {
      87             :     bc_state_updating_backup_t backup;
      88             : 
      89           0 :     if (bc_st_updating.in_progress) {
      90           0 :         backup.valid = 1;
      91           0 :         SAFE_MEMMOVE(&backup.data,
      92             :                      sizeof(backup.data),
      93             :                      MEMMOVE_ZERO_OFFSET,
      94             :                      &bc_st_updating,
      95             :                      sizeof(bc_st_updating),
      96             :                      MEMMOVE_ZERO_OFFSET,
      97             :                      sizeof(bc_st_updating),
      98             :                      { return; });
      99             : 
     100           0 :         NVM_WRITE(&N_bc_state_updating_backup,
     101             :                   &backup,
     102             :                   sizeof(N_bc_state_updating_backup));
     103             :     }
     104             : }
     105             : 
     106             : // -----------------------------------------------------------------------
     107             : // Blockchain state operations
     108             : // -----------------------------------------------------------------------
     109             : 
     110             : // Non-volatile blockchain validation state
     111             : NON_VOLATILE bc_state_t N_bc_state_var;
     112             : 
     113             : // Non-volatile intermediate advance blockchain state backup
     114             : NON_VOLATILE bc_state_updating_backup_t N_bc_state_updating_backup_var;
     115             : 
     116             : /*
     117             :  * Dump hash corresponding to hash_codes[hash_ix] to APDU.
     118             :  * @ret size of data dumped to APDU buffer
     119             :  */
     120         154 : uint8_t dump_hash(uint8_t hash_code) {
     121             :     const uint8_t* h;
     122         154 :     switch (hash_code) {
     123          22 :     case BEST_BLOCK:
     124          22 :         h = N_bc_state.best_block;
     125          22 :         break;
     126          22 :     case NEWEST_VALID_BLOCK:
     127          22 :         h = N_bc_state.newest_valid_block;
     128          22 :         break;
     129          22 :     case ANCESTOR_BLOCK:
     130          22 :         h = N_bc_state.ancestor_block;
     131          22 :         break;
     132          22 :     case ANCESTOR_RECEIPT_ROOT:
     133          22 :         h = N_bc_state.ancestor_receipt_root;
     134          22 :         break;
     135          22 :     case U_BEST_BLOCK:
     136          22 :         h = bc_st_updating.best_block;
     137          22 :         break;
     138          22 :     case U_NEWEST_VALID_BLOCK:
     139          22 :         h = bc_st_updating.newest_valid_block;
     140          22 :         break;
     141          22 :     case U_NEXT_EXPECTED_BLOCK:
     142          22 :         h = bc_st_updating.next_expected_block;
     143          22 :         break;
     144           0 :     default:
     145           0 :         FAIL(PROT_INVALID);
     146             :     }
     147             : 
     148         154 :     APDU_DATA_PTR[0] = hash_code;
     149         308 :     SAFE_MEMMOVE(APDU_DATA_PTR,
     150             :                  APDU_TOTAL_DATA_SIZE_OUT,
     151             :                  1,
     152             :                  h,
     153             :                  HASH_SIZE,
     154             :                  MEMMOVE_ZERO_OFFSET,
     155             :                  HASH_SIZE,
     156             :                  FAIL(PROT_INVALID));
     157             : 
     158         154 :     return 1 + HASH_SIZE;
     159             : }
     160             : 
     161             : /*
     162             :  * Dump difficulty to the APDU buffer. This function will copy to the
     163             :  * the buffer the bytes comprising the state's cumulative difficulty
     164             :  * in big endian order, with no leading zeroes.
     165             :  *
     166             :  * @ret number of bytes dumped to APDU buffer
     167             :  */
     168         800 : uint8_t dump_difficulty() {
     169             :     uint8_t buf[sizeof(bc_st_updating.total_difficulty)];
     170          22 :     dump_bigint_be(buf, bc_st_updating.total_difficulty, BIGINT_LEN);
     171          22 :     unsigned int start = 0;
     172         800 :     for (; start < sizeof(buf) && buf[start] == 0; start++)
     173         778 :         continue;
     174          44 :     SAFE_MEMMOVE(APDU_DATA_PTR,
     175             :                  APDU_TOTAL_DATA_SIZE_OUT,
     176             :                  MEMMOVE_ZERO_OFFSET,
     177             :                  buf,
     178             :                  sizeof(buf),
     179             :                  start,
     180             :                  sizeof(buf) - start,
     181             :                  FAIL(PROT_INVALID));
     182          22 :     return sizeof(buf) - start;
     183             : }
     184             : 
     185             : /*
     186             :  * Dump initial block hash to the specified APDU buffer data offset.
     187             :  *
     188             :  * @arg[in] offset APDU buffer data dump offset
     189             :  * @ret number of bytes dumped to APDU buffer
     190             :  */
     191           1 : uint8_t bc_dump_initial_block_hash(int offset) {
     192           2 :     SAFE_MEMMOVE(APDU_DATA_PTR,
     193             :                  APDU_TOTAL_DATA_SIZE_OUT,
     194             :                  offset,
     195             :                  INITIAL_BLOCK_HASH,
     196             :                  sizeof(INITIAL_BLOCK_HASH),
     197             :                  MEMMOVE_ZERO_OFFSET,
     198             :                  sizeof(INITIAL_BLOCK_HASH),
     199             :                  FAIL(PROT_INVALID));
     200           1 :     return sizeof(INITIAL_BLOCK_HASH);
     201             : }
     202             : 
     203             : /*
     204             :  * Dump blockchain state flags to APDU buffer.
     205             :  * @ret number of bytes dumped to buffer
     206             :  */
     207          22 : uint8_t dump_flags() {
     208          22 :     APDU_DATA_PTR[0] = bc_st_updating.in_progress;
     209          22 :     APDU_DATA_PTR[1] = bc_st_updating.already_validated;
     210          22 :     APDU_DATA_PTR[2] = bc_st_updating.found_best_block;
     211          22 :     return 3;
     212             : }
     213             : 
     214             : /*
     215             :  * Implement the get blockchain state procotol.
     216             :  *
     217             :  * @arg[in] rx number of received bytes from the Host
     218             :  * @ret        number of transmited bytes to the host
     219             :  */
     220         198 : unsigned int bc_get_state(volatile unsigned int rx) {
     221         198 :     uint8_t op = APDU_OP();
     222             : 
     223         198 :     uint8_t expected_data_size = op == OP_STATE_GET_HASH ? 1 : 0;
     224         198 :     if (APDU_DATA_SIZE(rx) != expected_data_size) {
     225           0 :         FAIL(PROT_INVALID);
     226             :     }
     227             : 
     228         198 :     if (op == OP_STATE_GET_HASH) {
     229         154 :         return TX_FOR_DATA_SIZE(dump_hash(APDU_DATA_PTR[0]));
     230             :     }
     231             : 
     232          44 :     if (op == OP_STATE_GET_DIFF) {
     233          22 :         return TX_FOR_DATA_SIZE(dump_difficulty());
     234             :     }
     235             : 
     236          22 :     if (op == OP_STATE_GET_FLAGS) {
     237          22 :         return TX_FOR_DATA_SIZE(dump_flags());
     238             :     }
     239             : 
     240           0 :     FAIL(PROT_INVALID);
     241             :     return 0;
     242             : }
     243             : 
     244             : /*
     245             :  * Implement the reset blockchain state protocol.
     246             :  *
     247             :  * @arg[in] rx number of received bytes from the Host
     248             :  * @ret        number of transmited bytes to the host
     249             :  */
     250          17 : unsigned int bc_reset_state(volatile unsigned int rx) {
     251          17 :     if (APDU_OP() != OP_STATE_RESET_INIT) {
     252           0 :         FAIL(PROT_INVALID);
     253             :     }
     254          17 :     if (APDU_DATA_SIZE(rx) != 0) {
     255           0 :         FAIL(PROT_INVALID);
     256             :     }
     257          17 :     RESET_BC_STATE();
     258          17 :     SET_APDU_OP(OP_STATE_RESET_DONE);
     259          17 :     return TX_NO_DATA();
     260             : }

Generated by: LCOV version 1.16