LCOV - code coverage report
Current view: top level - signer/src - bc_diff.c (source / functions) Hit Total Coverage
Test: powHSM firmware Lines: 30 47 63.8 %
Date: 2024-04-05 20:46:34 Functions: 3 6 50.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 "dbg.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_SIMULATOR)
      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             :  * Initialize a big integer. This is kind of tricky because the way big
      44             :  * integers are modeled in memory. Here goes an example:
      45             :  *
      46             :  * For the number:
      47             :  *
      48             :  *    [1c, 24, a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3]
      49             :  *
      50             :  * (that is, 0x1c24a0a1a2a3b0b1b2b3c0c1c2c3), we must build the following
      51             :  * array of uin32_t numbers:
      52             :  *
      53             :  *   [0xc0c1c2c3, 0xb0b1b2b3, 0xa0a1a2a3, 0x00001c24]
      54             :  *
      55             :  * This function implements exactly the conversion exemplified above.
      56             :  *
      57             :  * @arg[in] buf         buffer holding big integer bytes in big-endian order
      58             :  * @arg[in] buf_size    buffer size in bytes
      59             :  * @arg[out] target     big integer to initialize
      60             :  * @arg[in] target_size number of 32-byte integers comprising the big integer
      61             :  */
      62           5 : void bigint(const uint8_t* buf,
      63             :             uint16_t buf_size,
      64             :             DIGIT_T target[],
      65             :             uint16_t target_size) {
      66             : 
      67           5 :     mpSetZero(target, target_size);
      68           5 :     int j = 0, k = 0;
      69           5 :     DIGIT_T curr = 0;
      70         107 :     for (int i = buf_size - 1; i >= 0; i--) {
      71         102 :         curr = buf[i];
      72         102 :         target[j] |= (curr << (k * 8));
      73         102 :         if (++k == sizeof(DIGIT_T)) {
      74          24 :             ++j;
      75          24 :             k = 0;
      76             :         }
      77             :     }
      78           5 : }
      79             : 
      80             : /*
      81             :  * Store the given difficulty in the given big integer.
      82             :  *
      83             :  * @arg[in] diff_bytes bytes comprising difficulty
      84             :  * @arg[in] diff_size  number of bytes cmprising difficulty
      85             :  * @arg[in] difficulty big integer where difficulty will be store
      86             :  */
      87           0 : void store_difficulty(uint8_t* diff_bytes,
      88             :                       uint8_t diff_size,
      89             :                       DIGIT_T difficulty[]) {
      90           0 :     bigint(diff_bytes, diff_size, difficulty, BIGINT_LEN);
      91           0 : }
      92             : 
      93             : /*
      94             :  * Debug: dump a bigint to given buffer.
      95             :  *
      96             :  * @arg[in] buf  pointer to destination buffer
      97             :  * @arg[in] n    big integer to dump
      98             :  * @arg[in] size number of 32-byte integers comprising n
      99             :  */
     100           1 : void dump_bigint(uint8_t* buf, const DIGIT_T n[], const size_t size) {
     101           1 :     int k = 0;
     102          10 :     for (int i = size - 1; i >= 0; i--) {
     103           9 :         buf[k++] = (uint8_t)((n[i] & 0xff000000) >> 24);
     104           9 :         buf[k++] = (uint8_t)((n[i] & 0x00ff0000) >> 16);
     105           9 :         buf[k++] = (uint8_t)((n[i] & 0x0000ff00) >> 8);
     106           9 :         buf[k++] = (uint8_t)((n[i] & 0x000000ff) >> 0);
     107             :     }
     108           1 : }
     109             : 
     110             : static const DIGIT_T _2e256[] = {
     111             :     0x00,
     112             :     0x00,
     113             :     0x00,
     114             :     0x00,
     115             :     0x00,
     116             :     0x00,
     117             :     0x00,
     118             :     0x00,
     119             :     0x01,
     120             : };
     121             : 
     122             : /*
     123             :  * Check if BTC merge mining header matches block's difficulty.
     124             :  *
     125             :  * @arg[in] difficulty block difficulty
     126             :  * @arg[in] mm_hdr_hash BTC merge mining block hash
     127             :  *
     128             :  * @return
     129             :  *   DIFF_MATCH if BTC merge mining header matches block difficulty,
     130             :  *   DIFF_MISMATCH otherwise
     131             :  */
     132           3 : diff_result check_difficulty(DIGIT_T difficulty[], const uint8_t* mm_hdr_hash) {
     133             :     DIGIT_T target[BIGINT_LEN];
     134             :     DIGIT_T aux[BIGINT_LEN];
     135             : 
     136             :     // Taken from rskj:
     137             :     // minDifficulty is 3 because target needs to be of length 256
     138             :     // and not have 1 in the position 255 (count start from 0)
     139             :     // Implementation detail: to save memory we just remember
     140             :     // the first digit (least significant digit) of the original block
     141             :     // difficulty and then use the block difficulty to do the division
     142           3 :     DIGIT_T first_difficulty_digit = difficulty[0];
     143           3 :     mpSetDigit(aux, 3, BIGINT_LEN);
     144           3 :     int cmp = mpCompare_ct(difficulty, aux, BIGINT_LEN);
     145           3 :     if (cmp != 1) {
     146           0 :         mpSetDigit(difficulty, 3, BIGINT_LEN);
     147             :     }
     148             : 
     149           3 :     int r = mpDivide(target, aux, _2e256, BIGINT_LEN, difficulty, BIGINT_LEN);
     150             : 
     151           3 :     if (cmp != 1) {
     152           0 :         mpSetDigit(difficulty, first_difficulty_digit, BIGINT_LEN);
     153             :     }
     154             : 
     155             :     // Target = top/block_difficulty
     156             :     // int r = mpDivide(target, aux, _2e256, BIGINT_LEN, resultDifficulty,
     157             :     // BIGINT_LEN);
     158           3 :     if (r == -1) {
     159             :         // Divison by zero, report error
     160           0 :         return DIFF_ZERO;
     161             :     }
     162             : 
     163             :     // Turn BTC MM block hash into a big int
     164           3 :     bigint(mm_hdr_hash, HASH_SIZE, aux, BIGINT_LEN);
     165             : 
     166             :     // Block difficulty is invalid iif BTC MM block hash > target
     167             :     // BTC merge mining header (aux) matches block difficulty if
     168             :     // aux <= target. That is, if cmp != 1.
     169           3 :     cmp = mpCompare_ct(aux, target, BIGINT_LEN);
     170             : 
     171             :     LOG_BIGD_HEX("2^256 = ", _2e256, BIGINT_LEN, "\n");
     172             :     LOG_BIGD_HEX("Block difficulty = ", difficulty, BIGINT_LEN, "\n");
     173             :     LOG_BIGD_HEX("Target = ", target, BIGINT_LEN, "\n");
     174             :     LOG_BIGD_HEX("BTC MM block hash = ", aux, BIGINT_LEN, "\n");
     175             :     LOG("Difficulty is %s\n", cmp == 1 ? "not valid" : "valid");
     176             : 
     177           3 :     return cmp != 1 ? DIFF_MATCH : DIFF_MISMATCH;
     178             : }
     179             : 
     180             : /*
     181             :  * Cap block difficulty.
     182             :  *
     183             :  * @arg[in/out] difficulty the block difficulty to cap
     184             :  * @ret
     185             :  * 0 if capping ok (regardless of capping result)
     186             :  * BCDIFF_ERR_CAPPING if an error occurs
     187             :  */
     188           0 : int cap_block_difficulty(DIGIT_T difficulty[]) {
     189           0 :     int cmp = mpCompare_ct(difficulty, MAX_BLOCK_DIFFICULTY, BIGINT_LEN);
     190             : 
     191             :     LOG_BIGD_HEX("Block difficulty = ", difficulty, BIGINT_LEN, "\n");
     192             :     LOG_BIGD_HEX("Cap = ", MAX_BLOCK_DIFFICULTY, BIGINT_LEN, "\n");
     193             :     LOG("Block difficulty %s been capped\n", cmp == 1 ? "has" : "has NOT");
     194             : 
     195             :     // Block difficulty > Cap => Set block difficulty to cap
     196           0 :     if (cmp == 1) {
     197           0 :         SAFE_MEMMOVE(difficulty,
     198             :                      sizeof(DIGIT_T) * BIGINT_LEN,
     199             :                      MEMMOVE_ZERO_OFFSET,
     200             :                      MAX_BLOCK_DIFFICULTY,
     201             :                      sizeof(MAX_BLOCK_DIFFICULTY),
     202             :                      MEMMOVE_ZERO_OFFSET,
     203             :                      sizeof(MAX_BLOCK_DIFFICULTY),
     204             :                      { return BCDIFF_ERR_CAPPING; });
     205             :     }
     206             : 
     207           0 :     return 0;
     208             : }
     209             : 
     210             : /*
     211             :  * Accumulate difficulty.
     212             :  *
     213             :  * @arg[in] difficulty difficulty to accumulate
     214             :  * @arg[in/out] total_difficulty difficulty accumulator
     215             :  * @ret
     216             :  *   1 if there's carry
     217             :  *   0 if there's no carry
     218             :  *   BCDIFF_ERR_INVALID if an error occurs
     219             :  */
     220           0 : DIGIT_T accum_difficulty(DIGIT_T difficulty[], DIGIT_T total_difficulty[]) {
     221             :     DIGIT_T aux[BIGINT_LEN];
     222           0 :     DIGIT_T carry = mpAdd(aux, difficulty, total_difficulty, BIGINT_LEN);
     223             : 
     224             :     // This condition should never happen in the current implementation. This is
     225             :     // just a double-check to ensure that aux holds a valid value before
     226             :     // updating total_difficulty.
     227           0 :     if (carry == MAX_DIGIT)
     228           0 :         return BCDIFF_ERR_INVALID;
     229             : 
     230           0 :     SAFE_MEMMOVE(total_difficulty,
     231             :                  sizeof(DIGIT_T) * BIGINT_LEN,
     232             :                  MEMMOVE_ZERO_OFFSET,
     233             :                  aux,
     234             :                  sizeof(aux),
     235             :                  MEMMOVE_ZERO_OFFSET,
     236             :                  sizeof(DIGIT_T) * BIGINT_LEN,
     237             :                  { return BCDIFF_ERR_INVALID; });
     238             : 
     239           0 :     return carry;
     240             : }

Generated by: LCOV version 1.14