# Bundle Mining Review ## [IOTA Common](https://github.com/iotaledger/iota_common) [bundle_miner.h#L32](https://github.com/iotaledger/iota_common/blob/8cb88f3ff3188acc45457c80d47a369127ff9aaf/utils/bundle_miner.h#L32) `optimal_index_found_by_some_thread` must be made atomic to avoid race conditions as it is shared among multiple threads. [bundle_miner.c#L122](https://github.com/iotaledger/iota_common/blob/8cb88f3ff3188acc45457c80d47a369127ff9aaf/utils/bundle_miner.c#L122) This will overflow. `obsoleteTag` is 27 trytes, i.e. 128 bits. Storing it in a `uint64_t` (and adding count) will lead to arbitrary tags. Instead, just always start with `start_index = 0`. [bundle_miner.c#L57](https://github.com/iotaledger/iota_common/blob/8cb88f3ff3188acc45457c80d47a369127ff9aaf/utils/bundle_miner.c#L57) `mining_threshold` seems to be defined as $\log_3$ of the expected number of tries for an attacker. This logarithm is very unintuitive! The PoW difficulty is defined by powers of 3, but this threshold is not comparable to the PoW difficulty as it uses different hash function among others. It would be better and easier to maintain/understand to pass `num_trials_mining_threshold` (expected number of tries) directly. [bundle_miner.c#L76-L91](https://github.com/iotaledger/iota_common/blob/8cb88f3ff3188acc45457c80d47a369127ff9aaf/utils/bundle_miner.c#L76-L91) The if-clauses are completely unnecessary and don't do anything. Also the computation can be simplified. ```C double bundle_miner_probability_of_losing(byte_t const *const hash, uint8_t const security) { // compute the probablility that a random (not normalized) hash is tryte-wise <= the given hash double p = 1.0; for (size_t i = 0; i < security * NORMALIZED_FRAGMENT_LENGTH; i++) { p *= (double)(normalized_hash[i] - TRYTE_VALUE_MIN + 1) / (double)(TRYTE_VALUE_MAX - TRYTE_VALUE_MIN + 1); } return p; } ``` :::info Remark: Especially with security level 3 the probability `p` will get very small which might cause numerical issues. An alternative score computation would be for `(H,M) = (candidate_normalized, ctx->bundle_normalized_max)`: ``` score(H,M): s = 1.0 for i = 0 to security * 27: if H[i] > M[i]: s *= (14 + H[i])/(14 + M[i]) ``` This will result in exactly the same order as the probability but avoids small factors. ::: [bundle_miner.c#L58](https://github.com/iotaledger/iota_common/blob/8cb88f3ff3188acc45457c80d47a369127ff9aaf/utils/bundle_miner.c#L58) `optimal_index_found_by_some_thread` is not a good name, since only the *threshold* is reached. :::info Remark: It might make sense to add an early termination criterion, when an *optimal* index is found, i.e. `candidate_normalized` is tryte-wise less or equal to `ctx->bundle_normalized_max`. In this case, the new bundle will reveal *no* additional information at all. However, this is very unlikely and will only happen if multiple hashes have been signed already. ::: [bundle_miner.c#L105](https://github.com/iotaledger/iota_common/blob/8cb88f3ff3188acc45457c80d47a369127ff9aaf/utils/bundle_miner.c#L105) Rounds `count` up to the nearest multiple of `num_ctxs`. When `count` is already divisible it adds `num_ctxs`. Also, this will lead to overflows when a value close to `UINT32_MAX` is passed. This is not happening with the current parameters, but as an overflow could lead to unsecure bundles, those cases should be caught. [test_bundle_miner.c#L63](https://github.com/iotaledger/iota_common/blob/8cb88f3ff3188acc45457c80d47a369127ff9aaf/utils/tests/test_bundle_miner.c#L63) There is only one test for the actual mining and it only checks that the mined index matches. Since this is security relevant, it would be nice, to have better and more conclusive test cases here. For example: - Do not check the index, but check that the probability is indeed lower than for other indices. - Test for edge-cases like `MMM...MMM`, `NNN...NNN`, ... - Add a tests for the threshold termination. - Test more hashes. - ... ## [iota.js](https://github.com/chrisdukakis/iota.js/tree/feat/bundle-miner) https://github.com/chrisdukakis/iota.js/blob/82d5d6eb3ac858e6eb7dc361c07d5ac1c7a311e4/packages/bundle-miner/src/index.js#L19-L31 The function name is wrong and dangerous. It just computes the tryte-wise *maximum* of several hashes. - Change the function name to `maxHash`. - `MAX_TRYTE_VALUE` not needed, just compute the maximum. ## [trinity](https://github.com/laumair/trinity-wallet) https://github.com/laumair/trinity-wallet/blob/291091e2930ec7f7a2397c54ac3d036b32b6b575/src/desktop/src/libs/SeedStore/SeedStoreCore.js#L61 Where are those parameters coming from? - `miningThreshold`=40 corresponds to roughly 10^19 tries an attacker needs. This seems very high: Breaking security=1 with one known hash takes only 10^13 tries. Breaking security=2 with two known (random, not mined) hashes takes only 10^16 tries. Does this parameter ever lead to an early termination? Or is `count` always reached first? - `count`=10^8 seems rather arbitrary. Especially since the threshold does not seem to be very relevant this `count` defines the sole termination criterion. I see two potential issues with this: - on slow machines, computing `count` hashes can take a long time a "freeze" the mining - on fast machines, a higher security would be desirable and achievable - `isLedgerAccount ? count * 3.13 : count` what is this magic 3.13? If this is because the entire bundle hash needs to be `M` free, then this should be $\frac{3}{\texttt{security}}$. I think, these parameters should be revisited: - Carefully think about the `miningThreshold`: - How many hashes can a strong machine compute in one month or similar and use that value. - Make this dependent on the current probability, like 75% security that the currently known hashes provide. - No threshold at all, find the best hash possible within given timeout/count. - Combine the `count` termination criterion with a timer (or user interaction) to increase mining on very powerful hardware and decrease on lower power hardware.