uint64_t Currency::calculateInterest(uint64_t amount, uint32_t term, uint32_t height) const { assert(m_depositMinTerm <= term && term <= m_depositMaxTerm); assert(static_cast<uint64_t>(term)* m_depositMaxTotalRate > m_depositMinTotalRateFactor); uint64_t a = static_cast<uint64_t>(term) * m_depositMaxTotalRate - m_depositMinTotalRateFactor; uint64_t bHi; uint64_t bLo = mul128(amount, a, &bHi); uint64_t cHi; uint64_t cLo; assert(std::numeric_limits<uint32_t>::max() / 100 > m_depositMaxTerm); div128_32(bHi, bLo, static_cast<uint32_t>(100 * m_depositMaxTerm), &cHi, &cLo); assert(cHi == 0); //early depositor multiplier uint64_t interestHi; uint64_t interestLo; if (height <= CryptoNote::parameters::END_MULTIPLIER_BLOCK){ interestLo = mul128(cLo, CryptoNote::parameters::MULTIPLIER_FACTOR, &interestHi); assert(interestHi == 0); } else { interestHi = cHi; interestLo = cLo; } return interestLo; }
bool CodeInterval::update(const Interval& symbol) throw(not_normalized, invalid_symbol) { if(!is_normalized()) { throw not_normalized("Interval must be normalized before update."); } if(symbol.range < 3 || symbol.base + symbol.range < symbol.base) { throw invalid_symbol("Invalid symbol interval."); } // Calculate the new base uint64 h, l; std::tie(h, l) = mul128(symbol.base, range); std::tie(h, l) = add128(h, l, symbol.base); const uint64 t = h + (l > 0 ? 1 : 0); base += t; // Calculate the new range std::tie(h, l) = mul128(symbol.base + symbol.range, range); std::tie(h, l) = add128(h, l, symbol.base + symbol.range); std::tie(h, l) = add128(h, l, range); std::tie(h, l) = add128(h, l, 1); range = h - t - 1; // Return carry return base < t; }
//--------------------------------------------------------------------------------- bool tx_memory_pool::fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, uint64_t already_donated_coins, size_t &total_size, uint64_t &fee) { typedef transactions_container::value_type txv; CRITICAL_REGION_LOCAL(m_transactions_lock); std::vector<txv *> txs(m_transactions.size()); std::transform(m_transactions.begin(), m_transactions.end(), txs.begin(), [](txv &a) -> txv * { return &a; }); std::sort(txs.begin(), txs.end(), [](txv *a, txv *b) -> bool { uint64_t a_hi, a_lo = mul128(a->second.fee, b->second.blob_size, &a_hi); uint64_t b_hi, b_lo = mul128(b->second.fee, a->second.blob_size, &b_hi); return a_hi > b_hi || (a_hi == b_hi && a_lo > b_lo); }); size_t current_size = 0; uint64_t current_fee = 0; uint64_t best_money; uint64_t max_donation = 0; if (!get_block_reward(median_size, CURRENCY_COINBASE_BLOB_RESERVED_SIZE, already_generated_coins, already_donated_coins, best_money, max_donation)) { LOG_ERROR("Block with just a miner transaction is already too large!"); return false; } size_t best_position = 0; total_size = 0; fee = 0; std::unordered_set<crypto::key_image> k_images; for (size_t i = 0; i < txs.size(); i++) { txv &tx(*txs[i]); if(!is_transaction_ready_to_go(tx.second) || have_key_images(k_images, tx.second.tx)) { txs[i] = NULL; continue; } append_key_images(k_images, tx.second.tx); current_size += tx.second.blob_size; current_fee += tx.second.fee; uint64_t current_reward; if (!get_block_reward(median_size, current_size + CURRENCY_COINBASE_BLOB_RESERVED_SIZE, already_generated_coins, already_donated_coins, current_reward, max_donation)) { break; } if (best_money < current_reward + current_fee) { best_money = current_reward + current_fee; best_position = i + 1; total_size = current_size; fee = current_fee; } } for (size_t i = 0; i < best_position; i++) { if (txs[i]) { bl.tx_hashes.push_back(txs[i]->first); } } return true; }
//----------------------------------------------------------------------------------------------- uint64_t getPenalizedAmount(uint64_t amount, size_t medianSize, size_t currentBlockSize) { static_assert(sizeof(size_t) >= sizeof(uint32_t), "size_t is too small"); assert(currentBlockSize <= 2 * medianSize); assert(medianSize <= std::numeric_limits<uint32_t>::max()); assert(currentBlockSize <= std::numeric_limits<uint32_t>::max()); if (amount == 0) { return 0; } if (currentBlockSize <= medianSize) { return amount; } uint64_t productHi; uint64_t productLo = mul128(amount, currentBlockSize * (UINT64_C(2) * medianSize - currentBlockSize), &productHi); uint64_t penalizedAmountHi; uint64_t penalizedAmountLo; div128_32(productHi, productLo, static_cast<uint32_t>(medianSize), &penalizedAmountHi, &penalizedAmountLo); div128_32(penalizedAmountHi, penalizedAmountLo, static_cast<uint32_t>(medianSize), &penalizedAmountHi, &penalizedAmountLo); assert(0 == penalizedAmountHi); assert(penalizedAmountLo < amount); return penalizedAmountLo; }
bool decode_block(const char* block, size_t size, char* res) { assert(1 <= size && size <= full_encoded_block_size); int res_size = decoded_block_sizes[size]; if (res_size <= 0) return false; // Invalid block size uint64_t res_num = 0; uint64_t order = 1; for (size_t i = size - 1; i < size; --i) { int digit = reverse_alphabet(block[i]); if (digit < 0) return false; // Invalid symbol uint64_t product_hi; uint64_t tmp = res_num + mul128(order, (uint64_t) digit, &product_hi); if (tmp < res_num || 0 != product_hi) return false; // Overflow res_num = tmp; order *= alphabet_size; // Never overflows, 58^10 < 2^64 } if ((size_t)res_size < full_block_size && (UINT64_C(1) << (8 * res_size)) <= res_num) return false; // Overflow uint_64_to_8be(res_num, res_size, (uint8_t*)(res)); return true; }
//----------------------------------------------------------------------------------------------- uint64_t getPenalizedAmount(uint64_t amount, size_t medianSize, size_t currentBlockSize) { static_assert(sizeof(size_t) >= sizeof(uint32_t), "size_t is too small"); assert(currentBlockSize <= 2 * medianSize); assert(medianSize <= std::numeric_limits<uint32_t>::max()); assert(currentBlockSize <= std::numeric_limits<uint32_t>::max()); if (amount == 0) { return 0; } if (currentBlockSize <= medianSize) { return amount; } uint64_t productHi; //uint64_t productLo = mul128(amount, currentBlockSize * (UINT64_C(2) * medianSize - currentBlockSize), &productHi); //BUGFIX by Monero Project: 32-bit saturation bug (e.g. ARM7), the result was being treated as 32-bit by default uint64_t multiplicand = UINT64_C(2) * medianSize - currentBlockSize; multiplicand *= currentBlockSize; uint64_t productLo = mul128(amount, multiplicand, &productHi); uint64_t penalizedAmountHi; uint64_t penalizedAmountLo; div128_32(productHi, productLo, static_cast<uint32_t>(medianSize), &penalizedAmountHi, &penalizedAmountLo); div128_32(penalizedAmountHi, penalizedAmountLo, static_cast<uint32_t>(medianSize), &penalizedAmountHi, &penalizedAmountLo); assert(0 == penalizedAmountHi); assert(penalizedAmountLo < amount); return penalizedAmountLo; }
static inline void mul_sum_xor_dst(const uint8_t* a, uint8_t* c, uint8_t* dst) { uint64_t hi, lo = mul128(((uint64_t*) a)[0], ((uint64_t*) dst)[0], &hi) + ((uint64_t*) c)[1]; hi += ((uint64_t*) c)[0]; ((uint64_t*) c)[0] = ((uint64_t*) dst)[0] ^ hi; ((uint64_t*) c)[1] = ((uint64_t*) dst)[1] ^ lo; ((uint64_t*) dst)[0] = hi; ((uint64_t*) dst)[1] = lo; }
static void mul(const uint8_t* a, const uint8_t* b, uint8_t* res) { uint64_t a0, b0; uint64_t hi, lo; a0 = SWAP64LE(((uint64_t*) a)[0]); b0 = SWAP64LE(((uint64_t*) b)[0]); lo = mul128(a0, b0, &hi); ((uint64_t*) res)[0] = SWAP64LE(hi); ((uint64_t*) res)[1] = SWAP64LE(lo); }
difficulty_type Currency::nextDifficulty(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulativeDifficulties) const { assert(m_difficultyWindow >= 2); if (timestamps.size() > m_difficultyWindow) { timestamps.resize(m_difficultyWindow); cumulativeDifficulties.resize(m_difficultyWindow); } size_t length = timestamps.size(); assert(length == cumulativeDifficulties.size()); assert(length <= m_difficultyWindow); if (length <= 1) { return 1; } sort(timestamps.begin(), timestamps.end()); size_t cutBegin, cutEnd; assert(2 * m_difficultyCut <= m_difficultyWindow - 2); if (length <= m_difficultyWindow - 2 * m_difficultyCut) { cutBegin = 0; cutEnd = length; } else { cutBegin = (length - (m_difficultyWindow - 2 * m_difficultyCut) + 1) / 2; cutEnd = cutBegin + (m_difficultyWindow - 2 * m_difficultyCut); } assert(/*cut_begin >= 0 &&*/ cutBegin + 2 <= cutEnd && cutEnd <= length); uint64_t timeSpan = timestamps[cutEnd - 1] - timestamps[cutBegin]; if (timeSpan == 0) { timeSpan = 1; } difficulty_type totalWork = cumulativeDifficulties[cutEnd - 1] - cumulativeDifficulties[cutBegin]; assert(totalWork > 0); uint64_t low, high; low = mul128(totalWork, m_difficultyTarget, &high); if (high != 0 || low + timeSpan - 1 < low) { return 0; } return (low + timeSpan - 1) / timeSpan; }
void cryptonight_hash(const char* input, char* output, uint32_t len, int variant, uint64_t height) { struct cryptonight_ctx *ctx = alloca(sizeof(struct cryptonight_ctx)); hash_process(&ctx->state.hs, (const uint8_t*) input, len); memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); memcpy(ctx->aes_key, ctx->state.hs.b, AES_KEY_SIZE); ctx->aes_ctx = (oaes_ctx*) oaes_alloc(); size_t i, j; VARIANT1_INIT(); VARIANT2_INIT(ctx->b, ctx->state); VARIANT4_RANDOM_MATH_INIT(ctx->state); oaes_key_import_data(ctx->aes_ctx, ctx->aes_key, AES_KEY_SIZE); for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) { for (j = 0; j < INIT_SIZE_BLK; j++) { aesb_pseudo_round(&ctx->text[AES_BLOCK_SIZE * j], &ctx->text[AES_BLOCK_SIZE * j], ctx->aes_ctx->key->exp_data); } memcpy(&ctx->long_state[i * INIT_SIZE_BYTE], ctx->text, INIT_SIZE_BYTE); } for (i = 0; i < 16; i++) { ctx->a[i] = ctx->state.k[i] ^ ctx->state.k[32 + i]; ctx->b[i] = ctx->state.k[16 + i] ^ ctx->state.k[48 + i]; } for (i = 0; i < ITER / 2; i++) { /* Dependency chain: address -> read value ------+ * written value <-+ hard function (AES or MUL) <+ * next address <-+ */ /* Iteration 1 */ j = e2i(ctx->a); aesb_single_round(&ctx->long_state[j * AES_BLOCK_SIZE], ctx->c, ctx->a); VARIANT2_SHUFFLE_ADD(ctx->long_state, j * AES_BLOCK_SIZE, ctx->a, ctx->b, ctx->c); xor_blocks_dst(ctx->c, ctx->b, &ctx->long_state[j * AES_BLOCK_SIZE]); VARIANT1_1((uint8_t*)&ctx->long_state[j * AES_BLOCK_SIZE]); /* Iteration 2 */ j = e2i(ctx->c); uint64_t* dst = (uint64_t*)&ctx->long_state[j * AES_BLOCK_SIZE]; uint64_t t[2]; t[0] = dst[0]; t[1] = dst[1]; VARIANT2_INTEGER_MATH(t, ctx->c); copy_block(ctx->a1, ctx->a); VARIANT4_RANDOM_MATH(ctx->a, t, r, ctx->b, ctx->b + AES_BLOCK_SIZE); uint64_t hi; uint64_t lo = mul128(((uint64_t*)ctx->c)[0], t[0], &hi); VARIANT2_2(); VARIANT2_SHUFFLE_ADD(ctx->long_state, j * AES_BLOCK_SIZE, ctx->a1, ctx->b, ctx->c); ((uint64_t*)ctx->a)[0] += hi; ((uint64_t*)ctx->a)[1] += lo; dst[0] = ((uint64_t*)ctx->a)[0]; dst[1] = ((uint64_t*)ctx->a)[1]; ((uint64_t*)ctx->a)[0] ^= t[0]; ((uint64_t*)ctx->a)[1] ^= t[1]; VARIANT1_2((uint8_t*)&ctx->long_state[j * AES_BLOCK_SIZE]); copy_block(ctx->b + AES_BLOCK_SIZE, ctx->b); copy_block(ctx->b, ctx->c); } memcpy(ctx->text, ctx->state.init, INIT_SIZE_BYTE); oaes_key_import_data(ctx->aes_ctx, &ctx->state.hs.b[32], AES_KEY_SIZE); for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) { for (j = 0; j < INIT_SIZE_BLK; j++) { xor_blocks(&ctx->text[j * AES_BLOCK_SIZE], &ctx->long_state[i * INIT_SIZE_BYTE + j * AES_BLOCK_SIZE]); aesb_pseudo_round(&ctx->text[j * AES_BLOCK_SIZE], &ctx->text[j * AES_BLOCK_SIZE], ctx->aes_ctx->key->exp_data); } } memcpy(ctx->state.init, ctx->text, INIT_SIZE_BYTE); hash_permutation(&ctx->state.hs); /*memcpy(hash, &state, 32);*/ extra_hashes[ctx->state.hs.b[0] & 3](&ctx->state, 200, output); oaes_free((OAES_CTX **) &ctx->aes_ctx); }