Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement bignum system library using intx #530

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
31 changes: 31 additions & 0 deletions src/eei.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -845,4 +845,35 @@ void WasmEngine::collectBenchmarkingData()
}
return ret;
}

intx::uint256 EthereumInterface::loadBignum256(uint32_t srcOffset)
{
uint8_t data[32];
loadMemory(srcOffset, data, 32);
// FIXME: change this to little endian?
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intx only supports big endian right now: chfast/intx#78

return intx::be::uint256(data);
}

void EthereumInterface::storeBignum256(intx::uint256 const& src, uint32_t dstOffset)
{
uint8_t data[32];
// FIXME: change this to little endian?
intx::be::store(data, src);
storeMemory(data, dstOffset, 32);
}

void EthereumInterface::mul256(uint32_t aOffset, uint32_t bOffset, uint32_t retOffset)
{
storeBignum256(loadBignum256(aOffset) * loadBignum256(bOffset), retOffset);
}

void EthereumInterface::umulmod256(uint32_t aOffset, uint32_t bOffset, uint32_t modOffset, uint32_t retOffset)
{
using intx::uint512;
auto a = loadBignum256(aOffset);
auto b = loadBignum256(bOffset);
auto mod = loadBignum256(modOffset);
auto ret = mod != 0 ? ((uint512{a} * uint512{b}) % uint512{mod}).lo : 0;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

storeBignum256(ret, retOffset);
}
}
9 changes: 9 additions & 0 deletions src/eei.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include <evmc/evmc.h>
#include <evmc/evmc.hpp>

#include <intx/intx.hpp>

#include "exceptions.h"
#include "helpers.h"

Expand Down Expand Up @@ -163,6 +165,10 @@ class EthereumInterface {
uint32_t eeiCreate(uint32_t valueOffset, uint32_t dataOffset, uint32_t length, uint32_t resultOffset);
void eeiSelfDestruct(uint32_t addressOffset);

// Bignum system library
void mul256(uint32_t aOffset, uint32_t bOffset, uint32_t retOffset);
void umulmod256(uint32_t aOffset, uint32_t bOffset, uint32_t modOffset, uint32_t retOffset);

private:
void eeiRevertOrFinish(bool revert, uint32_t offset, uint32_t size);

Expand Down Expand Up @@ -191,6 +197,9 @@ class EthereumInterface {
evmc_uint256be loadUint128(uint32_t srcOffset);
void storeUint128(evmc_uint256be const& src, uint32_t dstOffset);

intx::uint256 loadBignum256(uint32_t srcOffset);
void storeBignum256(intx::uint256 const& src, uint32_t dstOffset);

inline int64_t maxCallGas(int64_t gas) { return gas - (gas / 64); }

/* Checks for overflow and safely charges gas for variable length data copies */
Expand Down
64 changes: 64 additions & 0 deletions src/wabt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,39 @@ ExecutionResult WabtEngine::execute(
}
);

// Create the bignum host module
// The lifecycle of this pointer is handled by `env`.
hostModule = env.AppendHostModule("bignum");
heraAssert(hostModule, "Failed to create host module.");

hostModule->AppendFuncExport(
"mul256",
{{Type::I32, Type::I32, Type::I32}, {}},
[&interface](
const interp::HostFunc*,
const interp::FuncSignature*,
const interp::TypedValues& args,
interp::TypedValues&
) {
interface.mul256(args[0].value.i32, args[1].value.i32, args[2].value.i32);
return interp::Result::Ok;
}
);

hostModule->AppendFuncExport(
"umulmod256",
{{Type::I32, Type::I32, Type::I32, Type::I32}, {}},
[&interface](
const interp::HostFunc*,
const interp::FuncSignature*,
const interp::TypedValues& args,
interp::TypedValues&
) {
interface.umulmod256(args[0].value.i32, args[1].value.i32, args[2].value.i32, args[3].value.i32);
return interp::Result::Ok;
}
);

#if HERA_DEBUGGING
// Create debug host module
// The lifecycle of this pointer is handled by `env`.
Expand Down Expand Up @@ -1112,6 +1145,37 @@ void WabtEngine::verifyContract(bytes_view code) {
}
);

// Create the bignum host module
// The lifecycle of this pointer is handled by `env`.
hostModule = env.AppendHostModule("bignum");
heraAssert(hostModule, "Failed to create host module.");

hostModule->AppendFuncExport(
"mul256",
{{Type::I32, Type::I32, Type::I32}, {}},
[&](
const interp::HostFunc*,
const interp::FuncSignature*,
const interp::TypedValues&,
interp::TypedValues&
) {
return interp::Result::Ok;
}
);

hostModule->AppendFuncExport(
"umulmod256",
{{Type::I32, Type::I32, Type::I32, Type::I32}, {}},
[&](
const interp::HostFunc*,
const interp::FuncSignature*,
const interp::TypedValues&,
interp::TypedValues&
) {
return interp::Result::Ok;
}
);

#if HERA_DEBUGGING
// Create debug host module
// The lifecycle of this pointer is handled by `env`.
Expand Down
20 changes: 19 additions & 1 deletion src/wavm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,20 @@ namespace wavm_host_module {
interface.top()->eeiSelfDestruct(addressOffset);
}

// the host module is called 'bignum'
DEFINE_INTRINSIC_MODULE(bignum)

// host functions follow
DEFINE_INTRINSIC_FUNCTION(bignum, "mul256", void, mul256, U32 a, U32 b, U32 ret)
{
interface.top()->mul256(a, b, ret);
}

DEFINE_INTRINSIC_FUNCTION(bignum, "umulmod256", void, umulmod246, U32 a, U32 b, U32 mod, U32 ret)
{
interface.top()->umulmod256(a, b, mod, ret);
}

// this is needed for resolving names of imported host functions
struct HeraWavmResolver : Runtime::Resolver {
HashMap<string, Runtime::ModuleInstance*> moduleNameToInstanceMap;
Expand Down Expand Up @@ -349,10 +363,14 @@ ExecutionResult WavmEngine::internalExecute(
Runtime::GCPointer<Runtime::ModuleInstance> ethereumHostModule = Intrinsics::instantiateModule(compartment, wavm_host_module::INTRINSIC_MODULE_REF(ethereum), "ethereum", {});
heraAssert(ethereumHostModule, "Failed to create host module.");

Runtime::GCPointer<Runtime::ModuleInstance> bignumHostModule = Intrinsics::instantiateModule(compartment, wavm_host_module::INTRINSIC_MODULE_REF(bignum), "bignum", {});
heraAssert(bignumHostModule, "Failed to create host module.");

// prepare contract module to resolve links against host module
wavm_host_module::HeraWavmResolver resolver;
// TODO: move this into the constructor?
resolver.moduleNameToInstanceMap.set("ethereum", ethereumHostModule);
resolver.moduleNameToInstanceMap.set("bignum", bignumHostModule);
Runtime::LinkResult linkResult = Runtime::linkModule(moduleIR, resolver);
ensureCondition(linkResult.success, ContractValidationFailure, "Couldn't link contract against host module.");

Expand Down Expand Up @@ -457,7 +475,7 @@ void WavmEngine::verifyContract(bytes_view code)

for (auto const& import: moduleIR.functions.imports) {
#if HERA_DEBUGGING
if (import.moduleName == "debug")
if (import.moduleName == "debug" || import.moduleName == "bignum")
continue;
#endif

Expand Down