Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 156 additions & 15 deletions lib/silkpre/precompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,120 @@
#include <silkpre/secp256k1n.hpp>
#include <silkpre/sha256.h>

enum {
/**
* EVM revision.
*
* The revision of the EVM specification based on the Ethereum
* upgrade / hard fork codenames.
*/
enum
{
/**
* The Frontier revision.
*
* The one Ethereum launched with.
*/
EVMC_FRONTIER = 0,

/**
* The Homestead revision.
*
* https://eips.ethereum.org/EIPS/eip-606
*/
EVMC_HOMESTEAD = 1,

/**
* The Tangerine Whistle revision.
*
* https://eips.ethereum.org/EIPS/eip-608
*/
EVMC_TANGERINE_WHISTLE = 2,

/**
* The Spurious Dragon revision.
*
* https://eips.ethereum.org/EIPS/eip-607
*/
EVMC_SPURIOUS_DRAGON = 3,

/**
* The Byzantium revision.
*
* https://eips.ethereum.org/EIPS/eip-609
*/
EVMC_BYZANTIUM = 4,

/**
* The Constantinople revision.
*
* https://eips.ethereum.org/EIPS/eip-1013
*/
EVMC_CONSTANTINOPLE = 5,

/**
* The Petersburg revision.
*
* Other names: Constantinople2, ConstantinopleFix.
*
* https://eips.ethereum.org/EIPS/eip-1716
*/
EVMC_PETERSBURG = 6,

/**
* The Istanbul revision.
*
* https://eips.ethereum.org/EIPS/eip-1679
*/
EVMC_ISTANBUL = 7,

/**
* The Berlin revision.
*
* https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/berlin.md
*/
EVMC_BERLIN = 8,

/**
* The London revision.
*
* https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/london.md
*/
EVMC_LONDON = 9,

/**
* The Paris revision (aka The Merge).
*
* https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md
*/
EVMC_PARIS = 10,

/**
* The Shanghai revision.
*
* https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md
*/
EVMC_SHANGHAI = 11,

/**
* The Cancun revision.
*
* https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/cancun.md
*/
EVMC_CANCUN = 12,

/**
* The Prague / Pectra revision.
*
* https://eips.ethereum.org/EIPS/eip-7600
*/
EVMC_PRAGUE = 13,

/**
* The Osaka / Fusaka revision.
*
* https://eips.ethereum.org/EIPS/eip-7607
*/
EVMC_OSAKA = 14,
};

static void right_pad(std::basic_string<uint8_t>& str, const size_t min_size) noexcept {
Expand Down Expand Up @@ -115,8 +226,40 @@ static intx::uint256 mult_complexity_eip2565(const intx::uint256& max_length) no
return words * words;
}

static intx::uint256 mult_complexity_eip7883(const intx::uint256& max_length) noexcept {
const intx::uint256 words{(max_length + 7) >> 3}; // ⌈max_length/8⌉
if (max_length > 32) {
return 2 * words * words;
} else {
return 16;
}
}

static intx::uint256 expmod_iteration_count(intx::uint256 exp_len256, unsigned bit_len, int rev) noexcept {
intx::uint256 adjusted_exponent_len{0};
if (exp_len256 > 32) {
const intx::uint256 exp_mult{rev < EVMC_OSAKA ? 8u : 16u};
adjusted_exponent_len = exp_mult * (exp_len256 - 32);
}
if (bit_len > 1) {
adjusted_exponent_len += bit_len - 1;
}

return std::max(adjusted_exponent_len, intx::uint256{1});
}

static uint64_t expmod_min_gas(int rev) {
if (rev < EVMC_BERLIN) {
return 0; // Prior to Berlin, minimum gas is 0.
} else if (rev < EVMC_OSAKA) {
return 200; // From Berlin to pre-Osaka (Prague), minimum gas is 200.
} else {
return 500; // From Osaka onwards, minimum gas is 500.
}
}

uint64_t silkpre_expmod_gas(const uint8_t* ptr, size_t len, int rev) {
const uint64_t min_gas{rev < EVMC_BERLIN ? 0 : 200u};
const uint64_t min_gas{expmod_min_gas(rev)};

std::basic_string<uint8_t> input(ptr, len);
right_pad(input, 3 * 32);
Expand All @@ -132,6 +275,12 @@ uint64_t silkpre_expmod_gas(const uint8_t* ptr, size_t len, int rev) {
if (intx::count_significant_words(base_len256) > 1 || intx::count_significant_words(exp_len256) > 1 ||
intx::count_significant_words(mod_len256) > 1) {
return UINT64_MAX;
} else if (rev >= EVMC_OSAKA) {
// EIP-7823: each of the length inputs (base, exponent and modulus) MUST
// be less than or equal to 8192 bits (1024 bytes).
if (base_len256 > 1024 || exp_len256 > 1024 || mod_len256 > 1024) {
return UINT64_MAX;
}
}

uint64_t base_len64{static_cast<uint64_t>(base_len256)};
Expand All @@ -151,25 +300,17 @@ uint64_t silkpre_expmod_gas(const uint8_t* ptr, size_t len, int rev) {
}
unsigned bit_len{256 - clz(exp_head)};

intx::uint256 adjusted_exponent_len{0};
if (exp_len256 > 32) {
adjusted_exponent_len = 8 * (exp_len256 - 32);
}
if (bit_len > 1) {
adjusted_exponent_len += bit_len - 1;
}

if (adjusted_exponent_len < 1) {
adjusted_exponent_len = 1;
}
const intx::uint256 iteration_count{expmod_iteration_count(exp_len256, bit_len, rev)};

const intx::uint256 max_length{std::max(mod_len256, base_len256)};

intx::uint256 gas;
if (rev < EVMC_BERLIN) {
gas = mult_complexity_eip198(max_length) * adjusted_exponent_len / 20;
gas = mult_complexity_eip198(max_length) * iteration_count / 20;
} else if (rev < EVMC_OSAKA) {
gas = mult_complexity_eip2565(max_length) * iteration_count / 3;
} else {
gas = mult_complexity_eip2565(max_length) * adjusted_exponent_len / 3;
gas = mult_complexity_eip2565(max_length) * iteration_count;
}

if (intx::count_significant_words(gas) > 1) {
Expand Down