LCOV - code coverage report
Current view: top level - powhsm/src - bc_diff.c (source / functions) Hit Total Coverage
Test: powHSM firmware Lines: 34 36 94.4 %
Date: 2025-07-10 13:49:13 Functions: 4 4 100.0 %

          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_diff.h"
      28             : #include "hal/log.h"
      29             : #include "memutil.h"
      30             : 
      31             : // Maximum difficulty for block difficulty capping (network dependent)
      32             : #ifdef TESTNET
      33             : static const DIGIT_T MAX_BLOCK_DIFFICULTY[BIGINT_LEN] = BCDIFF_MBD_TESTNET;
      34             : #elif defined(REGTEST)
      35             : static const DIGIT_T MAX_BLOCK_DIFFICULTY[BIGINT_LEN] = BCDIFF_MBD_REGTEST;
      36             : #elif defined(HSM_PLATFORM_X86)
      37             : DIGIT_T MAX_BLOCK_DIFFICULTY[BIGINT_LEN];
      38             : #else
      39             : static const DIGIT_T MAX_BLOCK_DIFFICULTY[BIGINT_LEN] = BCDIFF_MBD_MAINNET;
      40             : #endif
      41             : 
      42             : /*
      43             :  * Store the given difficulty in the given big integer.
      44             :  *
      45             :  * @arg[in] diff_bytes bytes comprising difficulty
      46             :  * @arg[in] diff_size  number of bytes cmprising difficulty
      47             :  * @arg[in] difficulty big integer where difficulty will be store
      48             :  */
      49         298 : void store_difficulty(uint8_t* diff_bytes,
      50             :                       uint8_t diff_size,
      51             :                       DIGIT_T difficulty[]) {
      52         298 :     parse_bigint_be(diff_bytes, diff_size, difficulty, BIGINT_LEN);
      53         298 : }
      54             : 
      55             : static const DIGIT_T _2e256[] = {
      56             :     0x00,
      57             :     0x00,
      58             :     0x00,
      59             :     0x00,
      60             :     0x00,
      61             :     0x00,
      62             :     0x00,
      63             :     0x00,
      64             :     0x01,
      65             : };
      66             : 
      67             : /*
      68             :  * Check if BTC merge mining header matches block's difficulty.
      69             :  *
      70             :  * @arg[in] difficulty block difficulty
      71             :  * @arg[in] mm_hdr_hash BTC merge mining block hash
      72             :  *
      73             :  * @return
      74             :  *   DIFF_MATCH if BTC merge mining header matches block difficulty,
      75             :  *   DIFF_MISMATCH otherwise
      76             :  */
      77         295 : diff_result check_difficulty(DIGIT_T difficulty[], const uint8_t* mm_hdr_hash) {
      78             :     DIGIT_T target[BIGINT_LEN];
      79             :     DIGIT_T aux[BIGINT_LEN];
      80             : 
      81             :     // Taken from rskj:
      82             :     // minDifficulty is 3 because target needs to be of length 256
      83             :     // and not have 1 in the position 255 (count start from 0)
      84             :     // Implementation detail: to save memory we just remember
      85             :     // the first digit (least significant digit) of the original block
      86             :     // difficulty and then use the block difficulty to do the division
      87         295 :     DIGIT_T first_difficulty_digit = difficulty[0];
      88         295 :     mpSetDigit(aux, 3, BIGINT_LEN);
      89         295 :     int cmp = mpCompare_ct(difficulty, aux, BIGINT_LEN);
      90         295 :     if (cmp != 1) {
      91         269 :         mpSetDigit(difficulty, 3, BIGINT_LEN);
      92             :     }
      93             : 
      94         295 :     int r = mpDivide(target, aux, _2e256, BIGINT_LEN, difficulty, BIGINT_LEN);
      95             : 
      96         295 :     if (cmp != 1) {
      97         269 :         mpSetDigit(difficulty, first_difficulty_digit, BIGINT_LEN);
      98             :     }
      99             : 
     100             :     // Target = top/block_difficulty
     101             :     // int r = mpDivide(target, aux, _2e256, BIGINT_LEN, resultDifficulty,
     102             :     // BIGINT_LEN);
     103         295 :     if (r == -1) {
     104             :         // Divison by zero, report error
     105           0 :         return DIFF_ZERO;
     106             :     }
     107             : 
     108             :     // Turn BTC MM block hash into a big int
     109         295 :     parse_bigint_be(mm_hdr_hash, HASH_SIZE, aux, BIGINT_LEN);
     110             : 
     111             :     // Block difficulty is invalid iif BTC MM block hash > target
     112             :     // BTC merge mining header (aux) matches block difficulty if
     113             :     // aux <= target. That is, if cmp != 1.
     114         295 :     cmp = mpCompare_ct(aux, target, BIGINT_LEN);
     115             : 
     116         295 :     LOG_BIGD_HEX("2^256 = ", _2e256, BIGINT_LEN, "\n");
     117         295 :     LOG_BIGD_HEX("Block difficulty = ", difficulty, BIGINT_LEN, "\n");
     118         295 :     LOG_BIGD_HEX("Target = ", target, BIGINT_LEN, "\n");
     119         295 :     LOG_BIGD_HEX("BTC MM block hash = ", aux, BIGINT_LEN, "\n");
     120         295 :     LOG("Difficulty is %s\n", cmp == 1 ? "not valid" : "valid");
     121             : 
     122         295 :     return cmp != 1 ? DIFF_MATCH : DIFF_MISMATCH;
     123             : }
     124             : 
     125             : /*
     126             :  * Cap block difficulty.
     127             :  *
     128             :  * @arg[in/out] difficulty the block difficulty to cap
     129             :  * @ret
     130             :  * 0 if capping ok (regardless of capping result)
     131             :  * BCDIFF_ERR_CAPPING if an error occurs
     132             :  */
     133         168 : int cap_block_difficulty(DIGIT_T difficulty[]) {
     134         168 :     int cmp = mpCompare_ct(difficulty, MAX_BLOCK_DIFFICULTY, BIGINT_LEN);
     135             : 
     136         168 :     LOG_BIGD_HEX("Block difficulty = ", difficulty, BIGINT_LEN, "\n");
     137         168 :     LOG_BIGD_HEX("Cap = ", MAX_BLOCK_DIFFICULTY, BIGINT_LEN, "\n");
     138         168 :     LOG("Block difficulty %s been capped\n", cmp == 1 ? "has" : "has NOT");
     139             : 
     140             :     // Block difficulty > Cap => Set block difficulty to cap
     141         168 :     if (cmp == 1) {
     142           8 :         SAFE_MEMMOVE(difficulty,
     143             :                      sizeof(DIGIT_T) * BIGINT_LEN,
     144             :                      MEMMOVE_ZERO_OFFSET,
     145             :                      MAX_BLOCK_DIFFICULTY,
     146             :                      sizeof(MAX_BLOCK_DIFFICULTY),
     147             :                      MEMMOVE_ZERO_OFFSET,
     148             :                      sizeof(MAX_BLOCK_DIFFICULTY),
     149             :                      { return BCDIFF_ERR_CAPPING; });
     150             :     }
     151             : 
     152         168 :     return 0;
     153             : }
     154             : 
     155             : /*
     156             :  * Accumulate difficulty.
     157             :  *
     158             :  * @arg[in] difficulty difficulty to accumulate
     159             :  * @arg[in/out] total_difficulty difficulty accumulator
     160             :  * @ret
     161             :  *   1 if there's carry
     162             :  *   0 if there's no carry
     163             :  *   BCDIFF_ERR_INVALID if an error occurs
     164             :  */
     165         168 : DIGIT_T accum_difficulty(DIGIT_T difficulty[], DIGIT_T total_difficulty[]) {
     166             :     DIGIT_T aux[BIGINT_LEN];
     167         168 :     DIGIT_T carry = mpAdd(aux, difficulty, total_difficulty, BIGINT_LEN);
     168             : 
     169             :     // This condition should never happen in the current implementation. This is
     170             :     // just a double-check to ensure that aux holds a valid value before
     171             :     // updating total_difficulty.
     172         168 :     if (carry == MAX_DIGIT)
     173           0 :         return BCDIFF_ERR_INVALID;
     174             : 
     175         168 :     SAFE_MEMMOVE(total_difficulty,
     176             :                  sizeof(DIGIT_T) * BIGINT_LEN,
     177             :                  MEMMOVE_ZERO_OFFSET,
     178             :                  aux,
     179             :                  sizeof(aux),
     180             :                  MEMMOVE_ZERO_OFFSET,
     181             :                  sizeof(DIGIT_T) * BIGINT_LEN,
     182             :                  { return BCDIFF_ERR_INVALID; });
     183             : 
     184         168 :     return carry;
     185             : }

Generated by: LCOV version 1.16