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 : }
|