diff --git a/libsolutil/CMakeLists.txt b/libsolutil/CMakeLists.txt
index 485218999..390950ab9 100644
--- a/libsolutil/CMakeLists.txt
+++ b/libsolutil/CMakeLists.txt
@@ -20,6 +20,7 @@ set(sources
Keccak256.cpp
Keccak256.h
LazyInit.h
+ LEB128.h
picosha2.h
Result.h
SetOnce.h
diff --git a/libsolutil/LEB128.h b/libsolutil/LEB128.h
new file mode 100644
index 000000000..a156a09bd
--- /dev/null
+++ b/libsolutil/LEB128.h
@@ -0,0 +1,59 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see .
+*/
+// SPDX-License-Identifier: GPL-3.0
+#pragma once
+
+
+#include
+
+namespace solidity::util
+{
+
+inline bytes lebEncode(uint64_t _n)
+{
+ bytes encoded;
+ while (_n > 0x7f)
+ {
+ encoded.emplace_back(uint8_t(0x80 | (_n & 0x7f)));
+ _n >>= 7;
+ }
+ encoded.emplace_back(_n);
+ return encoded;
+}
+
+// signed right shift is an arithmetic right shift
+static_assert((-1 >> 1) == -1, "Arithmetic shift not supported.");
+
+inline bytes lebEncodeSigned(int64_t _n)
+{
+ // Based on https://github.com/llvm/llvm-project/blob/master/llvm/include/llvm/Support/LEB128.h
+ bytes result;
+ bool more;
+ do
+ {
+ uint8_t v = _n & 0x7f;
+ _n >>= 7;
+ more = !((((_n == 0) && ((v & 0x40) == 0)) || ((_n == -1) && ((v & 0x40) != 0))));
+ if (more)
+ v |= 0x80; // Mark this byte to show that more bytes will follow.
+ result.emplace_back(v);
+ }
+ while (more);
+ return result;
+}
+
+}
diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp
index 5746dfaaf..148ed2786 100644
--- a/libyul/backends/wasm/BinaryTransform.cpp
+++ b/libyul/backends/wasm/BinaryTransform.cpp
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
@@ -239,28 +240,6 @@ static map const builtins = {
{"i64.extend_i32_u", 0xad},
};
-bytes lebEncode(uint64_t _n)
-{
- bytes encoded;
- while (_n > 0x7f)
- {
- encoded.emplace_back(uint8_t(0x80 | (_n & 0x7f)));
- _n >>= 7;
- }
- encoded.emplace_back(_n);
- return encoded;
-}
-
-bytes lebEncodeSigned(int64_t _n)
-{
- if (_n >= 0 && _n < 0x40)
- return toBytes(uint8_t(uint64_t(_n) & 0xff));
- else if (-_n > 0 && -_n < 0x40)
- return toBytes(uint8_t(uint64_t(_n + 0x80) & 0xff));
- else
- return toBytes(uint8_t(0x80 | uint8_t(_n & 0x7f))) + lebEncodeSigned(_n / 0x80);
-}
-
bytes prefixSize(bytes _data)
{
size_t size = _data.size();
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 052929c09..caa587415 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -35,6 +35,7 @@ set(libsolutil_sources
libsolutil/JSON.cpp
libsolutil/Keccak256.cpp
libsolutil/LazyInit.cpp
+ libsolutil/LEB128.cpp
libsolutil/StringUtils.cpp
libsolutil/SwarmHash.cpp
libsolutil/UTF8.cpp
diff --git a/test/libsolutil/LEB128.cpp b/test/libsolutil/LEB128.cpp
new file mode 100644
index 000000000..96ce11c7a
--- /dev/null
+++ b/test/libsolutil/LEB128.cpp
@@ -0,0 +1,101 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see .
+*/
+// SPDX-License-Identifier: GPL-3.0
+/**
+ * Unit tests for LEB128.
+ */
+
+#include
+
+#include
+
+using namespace std;
+
+namespace solidity::util::test
+{
+
+BOOST_AUTO_TEST_SUITE(LEB128Test)
+
+BOOST_AUTO_TEST_CASE(encode_unsigned)
+{
+ bytes zero = solidity::util::lebEncode(0);
+ BOOST_REQUIRE(zero.size() == 1);
+ BOOST_REQUIRE(zero[0] == 0x00);
+
+ bytes one = solidity::util::lebEncode(1);
+ BOOST_REQUIRE(one.size() == 1);
+ BOOST_REQUIRE(one[0] == 0x01);
+
+ bytes large = solidity::util::lebEncode(624485);
+ BOOST_REQUIRE(large.size() == 3);
+ BOOST_REQUIRE(large[0] == 0xE5);
+ BOOST_REQUIRE(large[1] == 0x8E);
+ BOOST_REQUIRE(large[2] == 0x26);
+
+ bytes larger = solidity::util::lebEncodeSigned(123456123456);
+ BOOST_REQUIRE(larger.size() == 6);
+ BOOST_REQUIRE(larger[0] == 0xC0);
+ BOOST_REQUIRE(larger[1] == 0xE4);
+ BOOST_REQUIRE(larger[2] == 0xBB);
+ BOOST_REQUIRE(larger[3] == 0xF4);
+ BOOST_REQUIRE(larger[4] == 0xCB);
+ BOOST_REQUIRE(larger[5] == 0x03);
+}
+
+BOOST_AUTO_TEST_CASE(encode_signed)
+{
+ bytes zero = solidity::util::lebEncodeSigned(0);
+ BOOST_REQUIRE(zero.size() == 1);
+ BOOST_REQUIRE(zero[0] == 0x00);
+
+ bytes one = solidity::util::lebEncodeSigned(1);
+ BOOST_REQUIRE(one.size() == 1);
+ BOOST_REQUIRE(one[0] == 0x01);
+
+ bytes negative_one = solidity::util::lebEncodeSigned(-1);
+ BOOST_REQUIRE(negative_one.size() == 1);
+ BOOST_REQUIRE(negative_one[0] == 0x7f);
+
+ bytes negative_two = solidity::util::lebEncodeSigned(-2);
+ BOOST_REQUIRE(negative_two.size() == 1);
+ BOOST_REQUIRE(negative_two[0] == 0x7e);
+
+ bytes large = solidity::util::lebEncodeSigned(624485);
+ BOOST_REQUIRE(large.size() == 3);
+ BOOST_REQUIRE(large[0] == 0xE5);
+ BOOST_REQUIRE(large[1] == 0x8E);
+ BOOST_REQUIRE(large[2] == 0x26);
+
+ bytes negative_large = solidity::util::lebEncodeSigned(-123456);
+ BOOST_REQUIRE(negative_large.size() == 3);
+ BOOST_REQUIRE(negative_large[0] == 0xC0);
+ BOOST_REQUIRE(negative_large[1] == 0xBB);
+ BOOST_REQUIRE(negative_large[2] == 0x78);
+
+ bytes negative_larger = solidity::util::lebEncodeSigned(-123456123456);
+ BOOST_REQUIRE(negative_larger.size() == 6);
+ BOOST_REQUIRE(negative_larger[0] == 0xC0);
+ BOOST_REQUIRE(negative_larger[1] == 0x9B);
+ BOOST_REQUIRE(negative_larger[2] == 0xC4);
+ BOOST_REQUIRE(negative_larger[3] == 0x8B);
+ BOOST_REQUIRE(negative_larger[4] == 0xB4);
+ BOOST_REQUIRE(negative_larger[5] == 0x7C);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}