From 010e3015dc2346ddce76c674fc9d1b6aff118223 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Thu, 24 Aug 2023 13:48:13 -0300 Subject: [PATCH] refactor: replace libb64 with custom base64 implementation --- Dockerfile | 2 +- README.md | 7 +- src/Makefile | 20 ++--- src/base64.cpp | 148 ++++++++++++++++++++++++++++---- tools/template/control.template | 2 +- 5 files changed, 143 insertions(+), 36 deletions(-) diff --git a/Dockerfile b/Dockerfile index b722c370f..e7cb1991b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ RUN apt-get update && \ libboost-filesystem1.81-dev libssl-dev libc-ares-dev zlib1g-dev \ ca-certificates automake libtool patchelf cmake pkg-config lua5.4 liblua5.4-dev \ libgrpc++-dev libprotobuf-dev protobuf-compiler-grpc \ - luarocks libb64-dev libcrypto++-dev nlohmann-json3-dev && \ + luarocks libcrypto++-dev nlohmann-json3-dev && \ update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 120 && \ update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-15 120 && \ rm -rf /var/lib/apt/lists/* diff --git a/README.md b/README.md index d20e28d90..28af0e83e 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ Docker targets: - Cryptopp >= 7.0.0 - GRPC >= 1.45.0 - Lua >= 5.4.4 -- b64 >= 1.2.1 - Boost >= 1.81 - nlohmann JSON >= 3.10 @@ -38,7 +37,7 @@ apt-get install build-essential wget git clang-tidy-15 clang-format-15 \ libboost-filesystem1.81-dev libssl-dev libc-ares-dev zlib1g-dev \ ca-certificates automake libtool patchelf cmake pkg-config lua5.4 liblua5.4-dev \ libgrpc++-dev libprotobuf-dev protobuf-compiler-grpc \ - luarocks libb64-dev libcrypto++-dev nlohmann-json3-dev + luarocks libcrypto++-dev nlohmann-json3-dev sudo luarocks install --lua-version=5.4 lpeg sudo luarocks install --lua-version=5.4 dkjson @@ -50,7 +49,7 @@ sudo luarocks install --lua-version=5.4 luaposix ##### MacPorts ``` -sudo port install clang-15 automake boost libtool wget cmake pkgconfig grpc zlib openssl lua libb64 libcryptopp nlohmann-json lua-luarocks +sudo port install clang-15 automake boost libtool wget cmake pkgconfig grpc zlib openssl lua libcryptopp nlohmann-json lua-luarocks sudo luarocks install --lua-version=5.4 lpeg sudo luarocks install --lua-version=5.4 dkjson @@ -61,7 +60,7 @@ sudo luarocks install --lua-version=5.4 luaposix ##### Homebrew ``` -brew install llvm@15 automake boost libomp wget cmake cryptopp pkg-config grpc zlib openssl lua@5.4 libb64 nlohmann-json luarocks +brew install llvm@15 automake boost libomp wget cmake cryptopp pkg-config grpc zlib openssl lua@5.4 nlohmann-json luarocks luarocks --lua-dir=$(brew --prefix)/opt/lua@5.4 install lpeg luarocks --lua-dir=$(brew --prefix)/opt/lua@5.4 install dkjson luarocks --lua-dir=$(brew --prefix)/opt/lua@5.4 install luasocket diff --git a/src/Makefile b/src/Makefile index 4c1ac7634..571873c50 100644 --- a/src/Makefile +++ b/src/Makefile @@ -69,8 +69,6 @@ BOOST_INC_Darwin=-I$(BREW_PREFIX)/include CRYPTOPP_LIB_Darwin:=-L$(BREW_PREFIX)/lib -lcryptopp CRYPTOPP_INC_Darwin:=-I$(BREW_PREFIX)/include NLOHMANN_JSON_INC_Darwin:=-I$(BREW_PREFIX)/include -B64_LIB_Darwin:=-L$(BREW_PREFIX)/lib -lb64 -B64_INC_Darwin:=-I$(BREW_PREFIX)/include GRPC_INC_Darwin:=$(shell pkg-config --cflags-only-I grpc++) GRPC_LIB_Darwin:=$(shell pkg-config --libs grpc++) PROTOBUF_INC_Darwin:=$(shell pkg-config --cflags-only-I protobuf) @@ -81,8 +79,6 @@ BOOST_LIB_DIR_Darwin=-L$(PORT_PREFIX)/libexec/boost/1.81/lib BOOST_INC_Darwin=-I$(PORT_PREFIX)/libexec/boost/1.81/include CRYPTOPP_LIB_Darwin:=-L$(PORT_PREFIX)/lib -lcryptopp CRYPTOPP_INC_Darwin:=-I$(PORT_PREFIX)/include -B64_LIB_Darwin:=-L$(PORT_PREFIX)/lib -lb64 -B64_INC_Darwin:=-I$(PORT_PREFIX)/include GRPC_INC_Darwin:=-I$(PORT_PREFIX)/include GRPC_LIB_Darwin=-L$(PORT_PREFIX)/lib -lgrpc++ -lgrpc -lgpr -lprotobuf -lpthread -labsl_synchronization PROTOBUF_INC_Darwin:=-I$(PORT_PREFIX)/include @@ -115,8 +111,6 @@ FS_LIB_Linux=-lstdc++fs BOOST_FILESYSTEM_LIB_Linux:=-lboost_system -lboost_filesystem BOOST_PROCESS_LIB_Linux:=-lpthread BOOST_INC_Linux= -B64_LIB_Linux:=-lb64 -B64_INC_Linux:= CRYPTOPP_LIB_Linux:=-lcryptopp CRYPTOPP_INC_Linux:= GRPC_INC_Linux:=$(shell pkg-config --cflags-only-I grpc++) @@ -141,8 +135,6 @@ SOLDFLAGS:=$(SOLDFLAGS_$(UNAME)) $(GCLDFLAGS) BOOST_PROCESS_LIB=$(BOOST_PROCESS_LIB_$(UNAME)) BOOST_FILESYSTEM_LIB=$(BOOST_FILESYSTEM_LIB_$(UNAME)) BOOST_INC=$(BOOST_INC_$(UNAME)) -B64_LIB=$(B64_LIB_$(UNAME)) -B64_INC=$(B64_INC_$(UNAME)) CRYPTOPP_LIB=$(CRYPTOPP_LIB_$(UNAME)) CRYPTOPP_INC=$(CRYPTOPP_INC_$(UNAME)) NLOHMANN_JSON_INC=$(NLOHMANN_JSON_INC_$(UNAME)) @@ -162,14 +154,14 @@ LIBCARTESI_GRPC_LDFLAGS=$(LIBCARTESI_GRPC_LDFLAGS_$(UNAME)) LIBCARTESI_GRPC_TESTS_LDFLAGS=$(LIBCARTESI_GRPC_TESTS_LDFLAGS_$(UNAME)) LIBCARTESI_GRPC_LIB=-L. -lcartesi_grpc-$(EMULATOR_VERSION_MAJOR).$(EMULATOR_VERSION_MINOR) -LIBCARTESI_LIBS:=$(CRYPTOPP_LIB) $(B64_LIB) +LIBCARTESI_LIBS:=$(CRYPTOPP_LIB) LIBCARTESI_GRPC_LIBS:=$(CRYPTOPP_LIB) $(GRPC_LIB) $(PROTOBUF_LIB) LUACARTESI_LIBS:=$(LIBCARTESI_LIB) $(CRYPTOPP_LIB) LUACARTESI_GRPC_LIBS:=$(LIBCARTESI_LIB) $(CRYPTOPP_LIB) $(LIBCARTESI_GRPC_LIB) -LUACARTESI_JSONRPC_LIBS:=$(LIBCARTESI_LIB) $(CRYPTOPP_LIB) $(B64_LIB) -REMOTE_CARTESI_MACHINE_LIBS:=$(CRYPTOPP_LIB) $(GRPC_LIB) $(PROTOBUF_LIB) $(B64_LIB) -JSONRPC_REMOTE_CARTESI_MACHINE_LIBS:=$(CRYPTOPP_LIB) $(B64_LIB) -TEST_MACHINE_C_API_LIBS:=$(LIBCARTESI_LIB) $(CRYPTOPP_LIB) $(LIBCARTESI_GRPC_LIB) $(BOOST_PROCESS_LIB) $(BOOST_FILESYSTEM_LIB) $(B64_LIB) +LUACARTESI_JSONRPC_LIBS:=$(LIBCARTESI_LIB) $(CRYPTOPP_LIB) +REMOTE_CARTESI_MACHINE_LIBS:=$(CRYPTOPP_LIB) $(GRPC_LIB) $(PROTOBUF_LIB) +JSONRPC_REMOTE_CARTESI_MACHINE_LIBS:=$(CRYPTOPP_LIB) +TEST_MACHINE_C_API_LIBS:=$(LIBCARTESI_LIB) $(CRYPTOPP_LIB) $(LIBCARTESI_GRPC_LIB) $(BOOST_PROCESS_LIB) $(BOOST_FILESYSTEM_LIB) HASH_LIBS:=$(CRYPTOPP_LIB) #DEFS+= -DMT_ALL_DIRTY @@ -178,7 +170,7 @@ WARNS=-W -Wall -pedantic # Place our include directories before the system's INCS=-I../lib/machine-emulator-defines -I../third-party/llvm-flang-uint128 \ - $(LUA_INC) $(CRYPTOPP_INC) $(NLOHMANN_JSON_INC) $(MONGOOSE_INC) $(B64_INC) $(BOOST_INC) $(PROTOBUF_INC) $(GRPC_INC) $(INCS_$(UNAME)) + $(LUA_INC) $(CRYPTOPP_INC) $(NLOHMANN_JSON_INC) $(MONGOOSE_INC) $(BOOST_INC) $(PROTOBUF_INC) $(GRPC_INC) $(INCS_$(UNAME)) ifeq ($(dump),yes) #DEFS+=-DDUMP_ILLEGAL_INSN_EXCEPTIONS diff --git a/src/base64.cpp b/src/base64.cpp index 559bcac92..9f49633ad 100644 --- a/src/base64.cpp +++ b/src/base64.cpp @@ -14,36 +14,152 @@ // with this program (see COPYING). If not, see . // +#include #include -#ifndef BUFFERSIZE -// To fulfill libb64's assumption that the macro BUFFERSIZE is always defined. It is not. -// bug https://sourceforge.net/p/libb64/bugs/3/ -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define BUFFERSIZE 1024 -#endif +#include "base64.h" -#include +namespace cartesi { -#include +// Base64 globals +static constexpr uint8_t b64base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -#include "base64.h" +static constexpr uint8_t b64unbase[] = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, + 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; -namespace cartesi { +// Acumulates bytes in input buffer until 3 bytes are available. +// Translate the 3 bytes into Base64 form and append to buffer. +// Returns new number of bytes in buffer. +static size_t b64encode(uint8_t c, uint8_t *input, size_t size, std::ostringstream &sout) { + input[size++] = c; + if (size == 3) { + uint8_t code[4]; + unsigned long value = 0; + value += input[0]; + value <<= 8; + value += input[1]; + value <<= 8; + value += input[2]; + code[3] = b64base[value & 0x3f]; + value >>= 6; + code[2] = b64base[value & 0x3f]; + value >>= 6; + code[1] = b64base[value & 0x3f]; + value >>= 6; + code[0] = b64base[value]; + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + sout << std::string_view(reinterpret_cast(code), 4); + size = 0; + } + return size; +} + +// Encodes the Base64 last 1 or 2 bytes and adds padding '=' +// Result, if any, is appended to buffer. +// Returns 0. +static size_t b64pad(const uint8_t *input, size_t size, std::ostringstream &sout) { + unsigned long value = 0; + uint8_t code[4] = {'=', '=', '=', '='}; + switch (size) { + case 1: + value = input[0] << 4; + code[1] = b64base[value & 0x3f]; + value >>= 6; + code[0] = b64base[value]; + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + sout << std::string_view(reinterpret_cast(code), 4); + break; + case 2: + value = input[0]; + value <<= 8; + value |= input[1]; + value <<= 2; + code[2] = b64base[value & 0x3f]; + value >>= 6; + code[1] = b64base[value & 0x3f]; + value >>= 6; + code[0] = b64base[value]; + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + sout << std::string_view(reinterpret_cast(code), 4); + break; + default: + break; + } + return 0; +} + +// Acumulates bytes in input buffer until 4 bytes are available. +// Translate the 4 bytes from Base64 form and append to buffer. +// Returns new number of bytes in buffer. +static size_t b64decode(uint8_t c, uint8_t *input, size_t size, std::ostringstream &sout) { + // ignore invalid characters + if (b64unbase[c] > 64) { + return size; + } + input[size++] = c; + // decode atom + if (size == 4) { + uint8_t decoded[3]; + int valid = 0; + int value = 0; + value = b64unbase[input[0]]; + value <<= 6; + value |= b64unbase[input[1]]; + value <<= 6; + value |= b64unbase[input[2]]; + value <<= 6; + value |= b64unbase[input[3]]; + decoded[2] = static_cast(value & 0xff); + value >>= 8; + decoded[1] = static_cast(value & 0xff); + value >>= 8; + decoded[0] = static_cast(value); + // take care of paddding + valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3; + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + sout << std::string_view(reinterpret_cast(decoded), valid); + return 0; + // need more data + } else { + return size; + } +} std::string encode_base64(const std::string &input) { - std::istringstream sin(input); std::ostringstream sout; - base64::encoder E; // NOLINT(clang-analyzer-optin.cplusplus.UninitializedObject) - E.encode(sin, sout); + uint8_t ctx[4]{}; + size_t ctxlen = 0; + size_t ncols = 0; + for (const char b : input) { + ctxlen = b64encode(static_cast(b), ctx, ctxlen, sout); + if (ctxlen == 0) { // appended 4 characters + ncols += 4; + if (ncols >= 72) { // add CRLF every 72 columns + sout << "\r\n"; + ncols = 0; + } + } + } + b64pad(ctx, ctxlen, sout); return sout.str(); } std::string decode_base64(const std::string &input) { - std::istringstream sin(input); std::ostringstream sout; - base64::decoder E; // NOLINT(clang-analyzer-optin.cplusplus.UninitializedObject) - E.decode(sin, sout); + uint8_t ctx[4]{}; + size_t ctxlen = 0; + for (const char b : input) { + ctxlen = b64decode(static_cast(b), ctx, ctxlen, sout); + } return sout.str(); } diff --git a/tools/template/control.template b/tools/template/control.template index 55bcbcb3e..5a96c3591 100644 --- a/tools/template/control.template +++ b/tools/template/control.template @@ -5,7 +5,7 @@ Homepage: https://docs.cartesi.io/machine/host/cmdline/ Architecture: ARG_ARCH Maintainer: Machine Reference Unit Provides: machine-emulator -Depends: libboost-context1.81.0, libboost-filesystem1.81.0, libreadline8, openssl, libc-ares2, zlib1g, ca-certificates, libgomp1, lua5.4, libb64-0d, libcrypto++8, libprotobuf32, libgrpc++1.51 +Depends: libboost-context1.81.0, libboost-filesystem1.81.0, libreadline8, openssl, libc-ares2, zlib1g, ca-certificates, libgomp1, lua5.4, libcrypto++8, libprotobuf32, libgrpc++1.51 Section: devel Priority: optional Multi-Arch: foreign