diff --git a/.cicd/defaults.json b/.cicd/defaults.json new file mode 100644 index 0000000000..9e15d6be2d --- /dev/null +++ b/.cicd/defaults.json @@ -0,0 +1,6 @@ +{ + "antelope-spring-dev":{ + "target":"main", + "prerelease":false + } + } \ No newline at end of file diff --git a/.cicd/platforms.json b/.cicd/platforms.json deleted file mode 100644 index 08910862ec..0000000000 --- a/.cicd/platforms.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "ubuntu18": { - "dockerfile": ".cicd/platforms/ubuntu18.Dockerfile" - }, - "ubuntu20": { - "dockerfile": ".cicd/platforms/ubuntu20.Dockerfile" - }, - "ubuntu22": { - "dockerfile": ".cicd/platforms/ubuntu22.Dockerfile" - } -} diff --git a/.cicd/platforms/ubuntu18.Dockerfile b/.cicd/platforms/ubuntu18.Dockerfile deleted file mode 100644 index 8f9c618be1..0000000000 --- a/.cicd/platforms/ubuntu18.Dockerfile +++ /dev/null @@ -1,31 +0,0 @@ -FROM ubuntu:bionic - -RUN apt-get update && apt-get upgrade -y && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential \ - g++-8 \ - curl \ - ninja-build \ - software-properties-common \ - zlib1g-dev \ - pkg-config \ - libboost-all-dev \ - libcurl4-gnutls-dev - -RUN curl -L https://cmake.org/files/v3.13/cmake-3.13.5.tar.gz | tar zx && \ - cd cmake-3.13.5 && \ - ./configure && \ - make -j$(nproc) install && \ - cd .. && \ - rm -rf cmake-3.13.5 - -RUN add-apt-repository ppa:git-core/ppa && apt update && apt install -y git - -RUN curl -L https://www.python.org/ftp/python/3.10.6/Python-3.10.6.tgz | tar zx && \ - cd Python* && \ - ./configure --enable-optimizations --prefix=/usr && \ - make -j$(nproc) install && \ - cd .. && \ - rm -rf Python* - -ENV CC=gcc-8 -ENV CXX=g++-8 diff --git a/.cicd/platforms/ubuntu22-llvm.Dockerfile b/.cicd/platforms/ubuntu22-llvm.Dockerfile new file mode 100644 index 0000000000..ff54bc3c98 --- /dev/null +++ b/.cicd/platforms/ubuntu22-llvm.Dockerfile @@ -0,0 +1,23 @@ +FROM ubuntu:jammy + +RUN apt-get update && apt-get upgrade -y && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential \ + cmake \ + wget \ + git \ + ninja-build \ + python3 \ + pkg-config \ + libboost-all-dev \ + libcurl4-gnutls-dev \ + lsb-release \ + software-properties-common \ + gnupg \ + clang-tidy + +RUN wget https://apt.llvm.org/llvm.sh +RUN chmod +x llvm.sh +RUN ./llvm.sh 16 + +ENV CC=clang-16 +ENV CXX=clang++-16 \ No newline at end of file diff --git a/.cicd/platforms/ubuntu24.Dockerfile b/.cicd/platforms/ubuntu24.Dockerfile new file mode 100644 index 0000000000..de1681197c --- /dev/null +++ b/.cicd/platforms/ubuntu24.Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:noble + +RUN apt-get update && apt-get upgrade -y && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential \ + cmake \ + git \ + ninja-build \ + python3 \ + pkg-config \ + libboost-all-dev \ + libcurl4-gnutls-dev \ + clang-tidy diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5345c2bfe1..88068cea7c 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -7,6 +7,17 @@ on: - "release/*" pull_request: workflow_dispatch: + inputs: + override-antelope-spring-dev: + description: Override antelope-spring-dev target + type: string + override-antelope-spring-dev-prerelease: + type: choice + description: Override antelope-spring-dev prelease + options: + - default + - true + - false permissions: packages: write @@ -17,73 +28,69 @@ defaults: shell: bash jobs: - d: - name: Discover Platforms + platform-cache: + name: Platform Cache + uses: AntelopeIO/platform-cache-workflow/.github/workflows/platformcache.yaml@v1 + permissions: + packages: write + contents: read + with: + runs-on: '["self-hosted", "enf-x86-beefy"]' + platform-files: .cicd/platforms + + versions: + name: Determine Versions runs-on: ubuntu-latest outputs: - missing-platforms: ${{steps.discover.outputs.missing-platforms}} - p: ${{steps.discover.outputs.platforms}} - steps: - - name: Discover Platforms - id: discover - uses: AntelopeIO/discover-platforms-action@v1 - with: - platform-file: .cicd/platforms.json - password: ${{secrets.GITHUB_TOKEN}} - package-name: builders - build-platforms: - name: Build Platforms - needs: d - if: needs.d.outputs.missing-platforms != '[]' - strategy: - fail-fast: false - matrix: - platform: ${{fromJSON(needs.d.outputs.missing-platforms)}} - runs-on: ["self-hosted", "enf-x86-beefy"] + antelope-spring-dev-target: ${{steps.versions.outputs.antelope-spring-dev-target}} + antelope-spring-dev-prerelease: ${{steps.versions.outputs.antelope-spring-dev-prerelease}} steps: - - name: Login to Container Registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{github.repository_owner}} - password: ${{secrets.GITHUB_TOKEN}} - - name: Build and push - uses: docker/build-push-action@v3 - with: - push: true - tags: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}} - file: ${{fromJSON(needs.d.outputs.p)[matrix.platform].dockerfile}} + - name: Setup versions from input or defaults + id: versions + env: + GH_TOKEN: ${{github.token}} + run: | + DEFAULTS_JSON=$(curl -sSfL $(gh api https://api.github.com/repos/${{github.repository}}/contents/.cicd/defaults.json?ref=${{github.sha}} --jq .download_url)) + echo antelope-spring-dev-target=$(echo "$DEFAULTS_JSON" | jq -r '."antelope-spring-dev".target') >> $GITHUB_OUTPUT + echo antelope-spring-dev-prerelease=$(echo "$DEFAULTS_JSON" | jq -r '."antelope-spring-dev".prerelease') >> $GITHUB_OUTPUT + + if [[ "${{inputs.override-antelope-spring-dev}}" != "" ]]; then + echo antelope-spring-dev-target=${{inputs.override-antelope-spring-dev}} >> $GITHUB_OUTPUT + fi + if [[ "${{inputs.override-antelope-spring-dev-prerelease}}" == +(true|false) ]]; then + echo antelope-spring-dev-prerelease=${{inputs.override-antelope-spring-dev-prerelease}} >> $GITHUB_OUTPUT + fi + Build: name: Build & Test - needs: [d, build-platforms] - if: always() && needs.d.result == 'success' && (needs.build-platforms.result == 'success' || needs.build-platforms.result == 'skipped') + needs: [platform-cache, versions] strategy: fail-fast: false matrix: - platform: [ubuntu18, ubuntu20, ubuntu22] + platform: [ubuntu20, ubuntu22, ubuntu22-llvm, ubuntu24] runs-on: ["self-hosted", "enf-x86-beefy"] - container: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}} + container: ${{fromJSON(needs.platform-cache.outputs.platforms)[matrix.platform].image}} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive - - name: Download leap-dev.deb (Ubuntu 20 only) - if: matrix.platform == 'ubuntu20' - uses: AntelopeIO/asset-artifact-download-action@v2 + - name: Download antelope-spring-dev.deb (Ubuntu 22 only) + if: matrix.platform == 'ubuntu22' + uses: AntelopeIO/asset-artifact-download-action@v3 with: owner: AntelopeIO - repo: leap - file: 'leap-dev.*(x86_64|amd64).deb' - target: 4.0 - artifact-name: leap-dev-ubuntu20-amd64 - container-package: experimental-binaries - token: ${{github.token}} - - name: Install leap-dev.deb (Ubuntu 20 only) - if: matrix.platform == 'ubuntu20' + repo: spring + file: 'antelope-spring-dev.*ubuntu22\.04_amd64.deb' + target: '${{needs.versions.outputs.antelope-spring-dev-target}}' + prereleases: ${{fromJSON(needs.versions.outputs.antelope-spring-dev-prerelease)}} + artifact-name: antelope-spring-dev-ubuntu22-amd64 + container-package: antelope-spring-experimental-binaries + - name: Install antelope-spring-dev.deb (Ubuntu 22 only) + if: matrix.platform == 'ubuntu22' run: | apt-get update && apt-get upgrade -y - apt install -y ./leap-dev*.deb - rm ./leap-dev*.deb + apt install -y ./antelope-spring-dev*.deb + rm ./antelope-spring-dev*.deb - name: Build & Test run: | mkdir build @@ -92,14 +99,14 @@ jobs: make -j $(nproc) cd tests ctest -j $(nproc) --output-on-failure - - name: Package (Ubuntu 18 only) - if: matrix.platform == 'ubuntu18' + - name: Package (Ubuntu 20 only) + if: matrix.platform == 'ubuntu20' run: | cd build/packages bash generate_package.sh deb ubuntu amd64 - - name: Upload (Ubuntu 18 only) - if: matrix.platform == 'ubuntu18' - uses: actions/upload-artifact@v3 + - name: Upload (Ubuntu 20 only) + if: matrix.platform == 'ubuntu20' + uses: actions/upload-artifact@v4 with: name: cdt_ubuntu_package_amd64 path: build/packages/cdt*amd64.deb diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000000..d5e26e02bc --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,33 @@ +name: Upload Release .deb + +on: + release: + types: [published] + +jobs: + eb: + name: Upload Release .deb + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + actions: read + steps: + - name: Get cdt.deb + id: getter + uses: AntelopeIO/asset-artifact-download-action@v3 + with: + owner: ${{github.repository_owner}} + repo: ${{github.event.repository.name}} + file: cdt_.*_amd64.deb + target: ${{github.sha}} + artifact-name: cdt_ubuntu_package_amd64 + wait-for-exact-target: true + - run: | + curl -LsSf \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{github.token}}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + -H "Content-Type: application/octet-stream" \ + --data-binary "@${{steps.getter.outputs.downloaded-file}}" \ + "https://uploads.github.com/repos/${{github.repository}}/releases/${{github.event.release.id}}/assets?name=${{steps.getter.outputs.downloaded-file}}" diff --git a/.gitmodules b/.gitmodules index 8c975eb8bc..ac62b95d85 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,4 +9,4 @@ url = https://github.com/AntelopeIO/cdt-libcxx [submodule "libraries/native/softfloat"] path = libraries/native/softfloat - url = https://github.com/AntelopeIO/berkeley-softfloat-3 \ No newline at end of file + url = https://github.com/AntelopeIO/berkeley-softfloat-3 diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c53deefe9..23cbcb2ded 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,9 +14,9 @@ endif() project(cdt) set(VERSION_MAJOR 4) -set(VERSION_MINOR 0) -set(VERSION_PATCH 1) -set(VERSION_SUFFIX "") +set(VERSION_MINOR 2) +set(VERSION_PATCH 0) +set(VERSION_SUFFIX "dev") if (VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") diff --git a/README.md b/README.md index 13d6fe834d..d150e3eccc 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ CDT currently supports Linux x86_64 Debian packages. Visit the [release page](ht Download the appropriate version of the Debian package and then install it. To download and install the latest version, run the following: ```sh -wget https://github.com/AntelopeIO/cdt/releases/download/v4.0.0/cdt_4.0.0_amd64.deb -sudo apt install ./cdt_4.0.0_amd64.deb +wget https://github.com/AntelopeIO/cdt/releases/download/v4.1.0/cdt_4.1.0_amd64.deb +sudo apt install ./cdt_4.1.0_amd64.deb ``` ### Debian package uninstall @@ -28,9 +28,9 @@ sudo apt remove cdt ## Building from source -Recent Ubuntu LTS releases are the only Linux distributions that we fully support. Other Linux distros and other POSIX operating systems (such as macOS) are tended to on a best-effort basis and may not be full featured. +Recent Ubuntu LTS releases are the only Linux distributions that we fully support. Other Linux distros and other POSIX operating systems (such as macOS) are tended to on a best-effort basis and may not be full featured. -The instructions below assume that you are building on Ubuntu 20.04. +The instructions below assume that you are building on Ubuntu 20.04. ### Install dependencies @@ -38,6 +38,7 @@ The instructions below assume that you are building on Ubuntu 20.04. apt-get update && apt-get install \ build-essential \ clang \ + clang-tidy \ cmake \ git \ libxml2-dev \ @@ -53,19 +54,19 @@ python3 -m pip install pygments ### Allowing integration tests to build -Integration tests require access to a build of [Leap](https://github.com/AntelopeIO/leap), a C++ implementation of the Antelope protocol. Simply installing Leap from a binary package will not be sufficient. +Integration tests require access to a build of [Spring](https://github.com/AntelopeIO/spring), a C++ implementation of the Antelope protocol. Simply installing Spring from a binary package will not be sufficient. -If you do not wish to build Leap, you can continue with building CDT but without building the integration tests. Otherwise, follow the instructions below before running `cmake`. +If you do not wish to build Spring, you can continue with building CDT but without building the integration tests. Otherwise, follow the instructions below before running `cmake`. -First, ensure that Leap has been built from source (see Leap's [README](https://github.com/AntelopeIO/leap#building-from-source) for details) and identify the build path, e.g. `/path/to/leap/build/`. +First, ensure that Spring has been built from source (see Spring's [README](https://github.com/AntelopeIO/spring#building-from-source) for details) and identify the build path, e.g. `/path/to/spring/build/`. Then, execute the following command in the same terminal session that you will use to build CDT: ```sh -export leap_DIR=/path/to/leap/build/lib/cmake/leap +export spring_DIR=/path/to/spring/build/lib/cmake/spring ``` -Now you can continue with the steps to build CDT as described. When you run `cmake` make sure that it does not report `leap package not found`. If it does, this means CDT was not able to find a build of Leap at the specified path in `leap_DIR` and will therefore continue without building the integration tests. +Now you can continue with the steps to build CDT as described. When you run `cmake` make sure that it does not report `spring package not found`. If it does, this means CDT was not able to find a build of Spring at the specified path in `spring_DIR` and will therefore continue without building the integration tests. ### ccache @@ -135,7 +136,7 @@ Installing CDT globally on your system will install the following tools in a loc * cdt-strip * eosio-pp * eosio-wasm2wast -* eosio-wast2wasm +* eosio-wast2wasm It will also install CMake files for CDT accessible within a `cmake/cdt` directory located within your system's `lib` directory. #### Manual installation diff --git a/docs/03_command-reference/cdt-cc.md b/docs/03_command-reference/cdt-cc.md index 913e940067..49bcbfe22e 100644 --- a/docs/03_command-reference/cdt-cc.md +++ b/docs/03_command-reference/cdt-cc.md @@ -47,7 +47,7 @@ compiler options: -finline-hint-functions - Inline functions which are (explicitly or implicitly) marked inline -fmerge-all-constants - Allow merging of constants -fnative - Compile and link for x86-64 - -fno-cfl-aa - Disable CFL Alias Analysis + -fcfl-aa - Enable CFL Alias Analysis -fno-elide-constructors - Disable C++ copy constructor elision -fno-lto - Disable LTO -fno-post-pass - Don't run post processing pass diff --git a/docs/03_command-reference/cdt-cpp.md b/docs/03_command-reference/cdt-cpp.md index 382f4f4857..3942513cd1 100644 --- a/docs/03_command-reference/cdt-cpp.md +++ b/docs/03_command-reference/cdt-cpp.md @@ -49,7 +49,7 @@ compiler options: -finline-hint-functions - Inline functions which are (explicitly or implicitly) marked inline -fmerge-all-constants - Allow merging of constants -fnative - Compile and link for x86-64 - -fno-cfl-aa - Disable CFL Alias Analysis + -cfl-aa - Enable CFL Alias Analysis -fno-elide-constructors - Disable C++ copy constructor elision -fno-lto - Disable LTO -fno-post-pass - Don't run post processing pass diff --git a/docs/03_command-reference/cdt-ld.md b/docs/03_command-reference/cdt-ld.md index f4339e91d2..8e3b2daa98 100644 --- a/docs/03_command-reference/cdt-ld.md +++ b/docs/03_command-reference/cdt-ld.md @@ -21,7 +21,7 @@ ld options: -L= - Add directory to library search path -fasm - Assemble file for x86-64 -fnative - Compile and link for x86-64 - -fno-cfl-aa - Disable CFL Alias Analysis + -fcfl-aa - Enable CFL Alias Analysis -fno-lto - Disable LTO -fno-post-pass - Don't run post processing pass -fno-stack-first - Don't set the stack first in memory diff --git a/docs/05_features/50_crypto-extensions.md b/docs/05_features/50_crypto-extensions.md index 414517be80..bb7100e3f5 100644 --- a/docs/05_features/50_crypto-extensions.md +++ b/docs/05_features/50_crypto-extensions.md @@ -1,23 +1,22 @@ --- -content_title: Crypto Extensions +content_title: Crypto Extensions API --- -As of `v3.0` crypto host functions were extended to include -- `mod_exp`: Big integer modular exponentiation -- `alt_bn128_add`, `alt_bn128_mul`, `alt_bn128_pair`: Add, multiply, and pairing check functions for the `alt_bn128` elliptic curve -- `blake2_f`: `BLAKE2b F` compression function -- `sha3`: sha3` hash function using `SHA3 NIST` -- `Keccak256`: `sha3` hash function using `SHA3 Keccak` -- `k1_recover`: Safe `ECDSA` uncompressed pubkey recover for the `secp256k1` curve -In `v3.0`, `C` format was supported; in `v3.1`, `C++` format was added for better data abstraction. +Antelope blockchain implements cryptographic functions for operations on points on elliptic curves, computing hashes +of big integers, big integer modular exponentiation, and other operations useful for implementing +cryptographic algorithms in your contracts. -## Prerequisites +In order to use the Crypto Extensions API you need to activate a protocol feature `CRYPTO_PRIMITIVES` +in `nodeos`. To do this you should call the following command in your command line: -- In `nodeos`, activate protocol feature `CRYPTO_PRIMITIVES` (`68d6405cb8df3de95bd834ebb408196578500a9f818ff62ccc68f60b932f7d82`) -- In smart contract code, include `crypto_ext.hpp` +`"cleos push action eosio activate ["6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc"] -p eosio@active"` -## C Format +And you need to include in the source code of your contract the following header: [crypto_ext.hpp](https://github.com/AntelopeIO/cdt/blob/main/libraries/eosiolib/core/eosio/crypto_ext.hpp) + +The header declares following basic plain C functions which implement the core functionality: + +## Plain C API - `int32_t alt_bn128_add( const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* result, uint32_t result_len )` Perform addition operation on the elliptic curve `alt_bn128`, store the result in `result`, and return `0` if success otherwise `-1` @@ -40,154 +39,92 @@ Test if the SHA3 keccak hash generated from data matches the provided digest - `int32_t k1_recover( const char* sig, uint32_t sig_len, const char* dig, uint32_t dig_len, char* pub, uint32_t pub_len )` Calculates the uncompressed public key used for a given signature on a given digest. Return `0` if success otherwise `-1` -## C++ Format -C++ types were added to represent `G1` and `G2` points (read and write) and views (read-only), and represent big integers. Their definitions are +Also, the header contains a set of handy C++ wrappers to simplify the contracts code. + +## C++ API + +`ec_point` type was added to represent `G1` and `G2` points on the elliptic curve. +`ec_point_view` type was added to provide a read-only interface for access to `G1` and `G2` points data. -### Types +### Data Types ```c++ - /** - * Abstracts mutable G1 and G2 points - * - */ + // Abstracts mutable G1 and G2 points template struct ec_point { - /** - * Bytes of the x coordinate - */ - std::vector x; - - /** - * Bytes of the y coordinate - */ - std::vector y; - - /** - * Construct a point given x and y - * - * @param x_ - The x coordinate, a vector of chars - * @param y_ - The y coordinate, a vector of chars - */ + std::vector x; // x coordinate + std::vector y; // y coordinate + // Construct from two coordinates represented by big integers ec_point(std::vector& x_, std::vector& y_); - - /** - * Construct a point given a serialized point - * - * @param p - The serialized point - */ + // Construct from a serialized point ec_point(std::vector& p); - - /** - * Return serialzed point containing only x and y - */ + // Return a serialized point containing only x and y std::vector serialized() const; }; - - /** - * Abstracts read-only G1 and G2 points - */ + + // Abstracts read-only G1 and G2 points template struct ec_point_view { - /** - * Pointer to the x coordinate - */ const char* x; - - /** - * Pointer to the y coordinate - */ const char* y; - - /** - * Number of bytes in each of x and y - */ + // Number of bytes in each of x and y uint32_t size; - - /** - * Construct a point view from x and y - * - * @param x_ - The x coordinate, poiter to chars - * @param x_size - x's size - * @param y_ - The y coordinate, poiter to chars - * @param y_size - y's size - */ + // Construct from two coordinates. Their sizes must be equal ec_point_view(const char* x_, uint32_t x_size, const char* y_, uint32_t y_size); - - /** - * Construct a point view from a serialized point - * - * @param p - The serialized point - */ + // Construct from a serialized point ec_point_view(const std::vector& p); - - /** - * Construct a point view from a point - * - * @param p - The point - */ + // Construct a point view from a point ec_point_view(const ec_point& p); - - /** - * Return serialzed point containing only x and y - */ + // Return serialized point containing only x and y std::vector serialized() const; }; - - static constexpr size_t g1_coordinate_size = 32; - static constexpr size_t g2_coordinate_size = 64; - - using g1_point = ec_point; - using g2_point = ec_point; - using g1_point_view = ec_point_view; - using g2_point_view = ec_point_view; - - /** - * Big integer. - * - * @ingroup crypto - */ - using bigint = std::vector; + + // Big integer. + using bigint = std::vector; ``` ### Methods -- `alt_bn128_add` +- Addition operation on the elliptic curve `alt_bn128` ```c++ template g1_point alt_bn128_add( const T& op1, const T& op2 ) ``` -Take two G1 points or G1 views as input and return a G1 point. -- `alt_bn128_mul` + +- Scalar multiplication operation on the elliptic curve `alt_bn128` ```c++ template g1_point alt_bn128_mul( const T& g1, const bigint& scalar) ``` -Take a G1 point or view and a bigint as input and return a G1 point -- `alt_bn128_pair` + +- Optimal-Ate pairing check elliptic curve `alt_bn128` ```c++ template int32_t alt_bn128_pair( const std::vector>& pairs ) ``` -Take a pair of G1 and G2 as input. -- `mod_exp` + +- Big integer modular exponentiation returns `( BASE^EXP ) % MOD` ```c++ int32_t mod_exp( const bigint& base, const bigint& exp, const bigint& mod, bigint& result ) ``` -Take bigints as input + +Please take a look into a [crypto_ext.hpp](https://github.com/AntelopeIO/cdt/blob/main/libraries/eosiolib/core/eosio/crypto_ext.hpp) +header file, it contains more wrappers and helper functions which may be useful in your code. ### Examples - `alt_bn128_add` ```c++ - std::vector x1, y1, x2, y2; + std::vector x1, y1, x2, y2; // Declare coordinates for points on an elliptic curve - // point + // Create the points on the curve eosio::g1_point point1 {x1, y1}; eosio::g1_point point2 {x2, y2}; + // Add two points and get a third point on the curve as result auto result = eosio::alt_bn128_add(point1, point2); - // view + // Do the same addition but with g1_point_view data types eosio::g1_point_view point_view1 {x1.data(), x1.size(), y1.data(), y1.size()}; eosio::g1_point_view point_view2 {x2.data(), x2.size(), y2.data(), y2.size()}; result = eosio::alt_bn128_add(point_view1, point_view2); @@ -195,32 +132,45 @@ Take bigints as input - `alt_bn128_mul` ```c++ - std::vector x, y, scaler; + // Declare coordinates for a point on an elliptic curve and a big integer + std::vector x, y, scalar; eosio::bigint s {scalar}; - // point + // Create the point object with given coordinates eosio::g1_point g1_point {x, y}; + // Multiply the point with a big integer and get a point on the curve as result auto result = eosio::alt_bn128_mul(g1_point, s); - // view + // Do the same multiplication but with g1_point_view data type eosio::g1_point_view g1_view {x.data(), x.size(), y.data(), y.size()}; result = eosio::alt_bn128_mul(g1_view, s); ``` - `alt_bn128_pair` ```c++ + // Declare coordinates for the pairs of points on an elliptic curve std::vector g1_a_x, g1_a_y, g2_a_x, g2_a_y, g1_b_x, g1_b_y, g2_b_x, g2_b_y; - // point + // Create the point object by given coordinates + // First pair eosio::g1_point g1_a {g1_a_x, g1_a_y}; eosio::g2_point g2_a {g2_a_x, g2_a_y}; + // Second pair eosio::g1_point g1_b {g1_b_x, g1_b_y}; eosio::g2_point g2_b {g2_b_x, g2_b_y}; + + // Create the pairs object std::vector> pairs { {g1_a, g2_a}, {g1_b, g2_b} }; + + // Perform the pairing check + // Return: + // -1 if there is an error + // 1 if the points not in a target group + // 0 if the points in a target group auto result = eosio::alt_bn128_pair(pairs); - // view + // Do the same pairing check but with g1_point_view and g2_point_view data types eosio::g1_point_view g1_view_a {g1_a_x.data(), g1_a_x.size(), g1_a_y.data(), g1_a_y.size()}; eosio::g2_point_view g2_view_a {g2_a_x.data(), g2_a_x.size(), g2_a_y.data(), g2_a_y.size()}; eosio::g1_point_view g1_view_b {g1_b_x.data(), g1_b_x.size(), g1_b_y.data(), g1_b_y.size()}; @@ -231,11 +181,14 @@ Take bigints as input - `mod_exp` ```c++ + // Declare big integer variables for the base, the exponent and the modulo std::vector base, exp, modulo; eosio::bigint base_val {base}; eosio::bigint exp_val {exp}; eosio::bigint modulo_val {modulo}; + // Declare and init a big integer variable for the result of exponentiation eosio::bigint result( modulo.size(), '\0' ); - + // Perform the exponentiation + // return -1 if there is an error otherwise 0 auto rc = eosio::mod_exp(base_val, exp_val, modulo_val, result); ``` diff --git a/docs/07_best-practices/08_abi/00_understanding-abi-files.md b/docs/07_best-practices/08_abi/00_understanding-abi-files.md index a5b33165a1..e63c794c1d 100644 --- a/docs/07_best-practices/08_abi/00_understanding-abi-files.md +++ b/docs/07_best-practices/08_abi/00_understanding-abi-files.md @@ -35,7 +35,7 @@ Start with an empty ABI, for exemplification we will work based on the `eosio.to An ABI enables any client or interface to interpret and even generate a GUI for your contract. For this to work consistently, describe the custom types that are used as a parameter in any public action or struct that needs to be described in the ABI. [[info | Built-in Types]] -| Antelope implements a number of custom built-ins. Built-in types don't need to be described in an ABI file. If you would like to familiarize yourself with Antelope's built-ins, they are defined [here](https://github.com/AntelopeIO/leap/blob/6817911900a088c60f91563995cf482d6b380b2d/libraries/chain/abi_serializer.cpp#L88-L129) +| Antelope implements a number of custom built-ins. Built-in types don't need to be described in an ABI file. If you would like to familiarize yourself with Antelope's built-ins, they are defined [here](https://github.com/AntelopeIO/spring/blob/5a3550a6fec4c1865e8aca07aa97693f720afe72/libraries/chain/abi_serializer.cpp#L92-L130) ```json diff --git a/docs/09_tutorials/03_create-an-abi-file.md b/docs/09_tutorials/03_create-an-abi-file.md index d82a57eb3e..199e78ecff 100644 --- a/docs/09_tutorials/03_create-an-abi-file.md +++ b/docs/09_tutorials/03_create-an-abi-file.md @@ -35,7 +35,7 @@ An ABI enables any client or interface to interpret and even generate an GUI for [[info]] |Built-in Types -Antelope implements a number of custom built-ins. Built-in types don't need to be described in an ABI file. If you would like to familiarize yourself with Antelope's built-ins, they are defined [here](https://github.com/AntelopeIO/leap/blob/6817911900a088c60f91563995cf482d6b380b2d/libraries/chain/abi_serializer.cpp#L88-L129). +Antelope implements a number of custom built-ins. Built-in types don't need to be described in an ABI file. If you would like to familiarize yourself with Antelope's built-ins, they are defined [here](https://github.com/AntelopeIO/spring/blob/5a3550a6fec4c1865e8aca07aa97693f720afe72/libraries/chain/abi_serializer.cpp#L92-L130). Using **eosio.token** as an example, the only type that requires a description in the ABI file is `account_name`. The ABI uses "new_type_name" to describe explicit types, in this case `account_name`, and `account_name` is an alias of `name` type. diff --git a/docs/man/cdt-cc.1.md b/docs/man/cdt-cc.1.md index 96d4b21563..e9c670a906 100644 --- a/docs/man/cdt-cc.1.md +++ b/docs/man/cdt-cc.1.md @@ -167,9 +167,9 @@ execution in Antelope block chain virtual machines. Compile and link for x86-64 -**`--fno-cfl-aa`** +**`--fcfl-aa`** - Disable CFL Alias Analysis + Enable CFL Alias Analysis **`--fno-elide-constructors`** diff --git a/docs/man/cdt-cpp.1.md b/docs/man/cdt-cpp.1.md index 95587afd0a..8a2a07f396 100644 --- a/docs/man/cdt-cpp.1.md +++ b/docs/man/cdt-cpp.1.md @@ -187,9 +187,9 @@ execution in Antelope block chain virtual machines. Compile and link for x86-64 -**`--fno-cfl-aa`** +**`--fcfl-aa`** - Disable CFL Alias Analysis + Enable CFL Alias Analysis **`--fno-elide-constructors`** diff --git a/docs/man/cdt-ld.1.md b/docs/man/cdt-ld.1.md index 7063e871bc..ad5ec25ca9 100644 --- a/docs/man/cdt-ld.1.md +++ b/docs/man/cdt-ld.1.md @@ -39,9 +39,9 @@ execution in Antelope block chain virtual machines. Compile and link for x86-64 -**`--fno-cfl-aa`** +**`--fcfl-aa`** - Disable CFL Alias Analysis + Enable CFL Alias Analysis **`--fno-lto`** diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 0000000000..f52d7547d4 --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,21 @@ +# Roadmap for CDT + +## Summary Milestone 5 +Top priority is clean-up of the code and optimizing for support. Target Date for Milestone 5 is May/June 2024. +- Remove AntlerProj repos from build and archive AntlerProj +- Move to C++20 - allow contracts to compile C++20 +- Vanilla Clang/LLVM +- Upgrade to LLVM + + +## Antler +We lack the resources to complete the Antler project and support it going forward. Removing dependencies will simplify the build process and simplify things. + +## Move to C++20 +Allow contracts to compile C++20. In addition to the benefits from the latest language features. Currently, ENF maintains an additional fork of one of our upstream dependencies for EOS EVM simply to get around the fact that the upstream assumes C++20 but we cannot build C++20 code in our contracts. + +## Vanilla Clang/LLVM +Try eosio extension free llvm and if it works with no issues then remove extensions to Clang/LLVM. The hope we will enable us to use Vanilla versions of the packages. This will allow us to use the latest, and will lead to improvements in functionality and performance. + +## Upgrade to LLVM 16 +Upgrade to the latest diff --git a/libraries/eosiolib/CMakeLists.txt b/libraries/eosiolib/CMakeLists.txt index a716dde5bb..857024d30e 100644 --- a/libraries/eosiolib/CMakeLists.txt +++ b/libraries/eosiolib/CMakeLists.txt @@ -4,6 +4,7 @@ file(GLOB HEADERS "*.hpp" add_library(eosio eosiolib.cpp crypto.cpp + base64.cpp ${HEADERS}) add_library(eosio_malloc @@ -40,6 +41,7 @@ if (ENABLE_NATIVE_COMPILER) eosiolib.cpp crypto.cpp malloc.cpp + base64.cpp ${HEADERS}) add_dependencies( native_eosio eosio ) diff --git a/libraries/eosiolib/base64.cpp b/libraries/eosiolib/base64.cpp new file mode 100644 index 0000000000..4dc5e2a7b2 --- /dev/null +++ b/libraries/eosiolib/base64.cpp @@ -0,0 +1,189 @@ +#include "core/eosio/base64.hpp" + +namespace eosio::detail { + +unsigned int pos_of_char(const unsigned char chr, bool url) { + // Return the position of chr within base64_encode() + constexpr unsigned char from_base64_chars[2][256] = { + { // for base64 + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 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, 64, 64, 64, 64, 64, + 64, 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, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + }, + { // for base64url + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 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, 64, 64, 64, 64, 63, + 64, 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, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + }}; + + auto c = from_base64_chars[url][chr]; + eosio::check(c != 64, "encountered non-base64 character"); + + return c; +} + +std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) { + + const size_t len_encoded = (in_len +2) / 3 * 4; + const unsigned char trailing_char = '='; + + // Includes performance improvement from unmerged PR: https://github.com/ReneNyffenegger/cpp-base64/pull/27 + + // Depending on the url parameter in base64_chars, one of + // two sets of base64 characters needs to be chosen. + // They differ in their last two characters. + const char* base64_chars[2] = { + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "+/", + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "-_"}; + + // Choose set of base64 characters. They differ + // for the last two positions, depending on the url + // parameter. + // A bool (as is the parameter url) is guaranteed + // to evaluate to either 0 or 1 in C++ therefore, + // the correct character set is chosen by subscripting + // base64_chars with url. + const char* base64_chars_ = base64_chars[url]; + + std::string ret; + ret.reserve(len_encoded); + + unsigned int pos = 0; + + while (pos < in_len) { + ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]); + + if (pos+1 < in_len) { + ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]); + + if (pos+2 < in_len) { + ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]); + ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]); + } + else { + ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]); + if (!url) ret.push_back(trailing_char); + } + } + else { + + ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]); + if (!url) ret.push_back(trailing_char); + if (!url) ret.push_back(trailing_char); + } + + pos += 3; + } + + + return ret; +} + +std::string base64_decode(std::string_view encoded_string, bool remove_linebreaks, bool url) { + if (encoded_string.empty()) return std::string{}; + + if (remove_linebreaks) { + + std::string copy(encoded_string); + + copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end()); + + return base64_decode(copy, false, url); + } + + size_t length_of_string = encoded_string.length(); + size_t pos = 0; + + // + // The approximate length (bytes) of the decoded string might be one or + // two bytes smaller, depending on the amount of trailing equal signs + // in the encoded string. This approximation is needed to reserve + // enough space in the string to be returned. + // + size_t approx_length_of_decoded_string = length_of_string / 4 * 3; + std::string ret; + ret.reserve(approx_length_of_decoded_string); + + while (pos < length_of_string) { + // + // Iterate over encoded input string in chunks. The size of all + // chunks except the last one is 4 bytes. + // + // The last chunk might be padded with equal signs or dots + // in order to make it 4 bytes in size as well, but this + // is not required as per RFC 2045. + // + // All chunks except the last one produce three output bytes. + // + // The last chunk produces at least one and up to three bytes. + // + eosio::check(pos+1 < length_of_string, "wrong encoded string size"); + size_t pos_of_char_1 = pos_of_char(encoded_string.at(pos+1), url); + + // + // Emit the first output byte that is produced in each chunk: + // + ret.push_back(static_cast( ( (pos_of_char(encoded_string.at(pos+0), url) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4))); + + if ( ( pos + 2 < length_of_string ) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045) + encoded_string.at(pos+2) != '=' && + encoded_string.at(pos+2) != '.' // accept URL-safe base 64 strings, too, so check for '.' also. + ) + { + // + // Emit a chunk's second byte (which might not be produced in the last chunk). + // + unsigned int pos_of_char_2 = pos_of_char(encoded_string.at(pos+2), url); + ret.push_back(static_cast( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2))); + + if ( ( pos + 3 < length_of_string ) && + encoded_string.at(pos+3) != '=' && + encoded_string.at(pos+3) != '.' + ) + { + // + // Emit a chunk's third byte (which might not be produced in the last chunk). + // + ret.push_back(static_cast( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string.at(pos+3), url))); + } + } + + pos += 4; + } + + return ret; +} + +}//eosio::detail diff --git a/libraries/eosiolib/capi/eosio/crypto.h b/libraries/eosiolib/capi/eosio/crypto.h index fff817b79b..6ace6c1b74 100644 --- a/libraries/eosiolib/capi/eosio/crypto.h +++ b/libraries/eosiolib/capi/eosio/crypto.h @@ -186,6 +186,29 @@ void sha512( const char* data, uint32_t length, struct capi_checksum512* hash ); __attribute__((eosio_wasm_import)) void ripemd160( const char* data, uint32_t length, struct capi_checksum160* hash ); +/** + * Verifies the RSA SHA-256 signature for a given message using the provided public key components (exponent and modulus). + * + * @param message - The original message that was signed. + * @param message_len - Length of the message in bytes. + * @param signature - The RSA signature to verify. + * @param signature_len - Length of the signature in bytes. + * @param exponent - The public key exponent. + * @param exponent_len - Length of the exponent in bytes. + * @param modulus - The public key modulus. + * @param modulus_len - Length of the modulus in bytes. + * @return int - Returns 1 if the signature is valid, 0 if invalid. + * + * Example: + * + * @code + * @endcode + */ +__attribute__((eosio_wasm_import)) +int32_t verify_rsa_sha256_sig( const void* message, uint32_t message_len, + const char* signature, uint32_t signature_len, + const char* exponent, uint32_t exponent_len, + const char* modulus, uint32_t modulus_len); /** * Calculates the public key used for a given signature and hash used to create a message. * diff --git a/libraries/eosiolib/capi/eosio/crypto_bls_ext.h b/libraries/eosiolib/capi/eosio/crypto_bls_ext.h new file mode 100644 index 0000000000..323dbbe6c2 --- /dev/null +++ b/libraries/eosiolib/capi/eosio/crypto_bls_ext.h @@ -0,0 +1,40 @@ +#pragma once +#include "types.h" +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((eosio_wasm_import)) +int32_t bls_g1_add(const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* res, uint32_t res_len); + +__attribute__((eosio_wasm_import)) +int32_t bls_g2_add(const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* res, uint32_t res_len); + +__attribute__((eosio_wasm_import)) +int32_t bls_g1_weighted_sum(const char* points, uint32_t points_len, const char* scalars, uint32_t scalars_len, uint32_t n, char* res, uint32_t res_len); + +__attribute__((eosio_wasm_import)) +int32_t bls_g2_weighted_sum(const char* points, uint32_t points_len, const char* scalars, uint32_t scalars_len, uint32_t n, char* res, uint32_t res_len); + +__attribute__((eosio_wasm_import)) +int32_t bls_pairing(const char* g1_points, uint32_t g1_points_len, const char* g2_points, uint32_t g2_points_len, uint32_t n, char* res, uint32_t res_len); + +__attribute__((eosio_wasm_import)) +int32_t bls_g1_map(const char* e, uint32_t e_len, char* res, uint32_t res_len); + +__attribute__((eosio_wasm_import)) +int32_t bls_g2_map(const char* e, uint32_t e_len, char* res, uint32_t res_len); + +__attribute__((eosio_wasm_import)) +int32_t bls_fp_mod(const char* s, uint32_t s_len, char* res, uint32_t res_len); + +__attribute__((eosio_wasm_import)) +int32_t bls_fp_mul(const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* res, uint32_t res_len); + +__attribute__((eosio_wasm_import)) +int32_t bls_fp_exp(const char* base, uint32_t base_len, const char* exp, uint32_t exp_len, char* res, uint32_t res_len); + +#ifdef __cplusplus +} +#endif + diff --git a/libraries/eosiolib/capi/eosio/instant_finality.h b/libraries/eosiolib/capi/eosio/instant_finality.h new file mode 100644 index 0000000000..9cabc260b3 --- /dev/null +++ b/libraries/eosiolib/capi/eosio/instant_finality.h @@ -0,0 +1,27 @@ +#pragma once +#include "types.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup instant_finality_c Instant_finality C API + * @ingroup c_api + * @brief Defines %C Instant_finality API + */ + +/** + * Submits a finalizer policy change to Instant Finality + * + * @param packed_finalizer_format - format of the finalizer_policy object, currently only supports 0 + * @param data - pointer finalizer_policy object packed as bytes + * @param len - size of packed finalazer_policy object + * @pre `data` is a valid pointer to a range of memory at least `len` bytes long that contains packed abi_finalizer_policy data + * abi_finalizer_policy structure is defined in instant_finality.hpp + */ +__attribute__((eosio_wasm_import)) +void set_finalizers( uint64_t packed_finalizer_format, const char* data, uint32_t len ); + +#ifdef __cplusplus +} +#endif diff --git a/libraries/eosiolib/capi/eosio/security_group.h b/libraries/eosiolib/capi/eosio/security_group.h deleted file mode 100644 index 9e362c63e6..0000000000 --- a/libraries/eosiolib/capi/eosio/security_group.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -#include "types.h" -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Propose new participants to the security group. - * - * @param data - the buffer containing the packed participants. - * @param datalen - size of the packed participants - * @pre `data` is a valid pointer to a range of memory at least `datalen` bytes long that contains packed participants data - * - * @return -1 if proposing a new security group was unsuccessful, otherwise returns 0. -*/ -__attribute__((eosio_wasm_import)) -int64_t add_security_group_participants(const char* data, uint32_t datalen); - -/** - * Propose to remove participants from the security group. - * - * @param data - the buffer containing the packed participants. - * @param datalen - size of the packed participants - * @pre `data` is a valid pointer to a range of memory at least `datalen` bytes long that contains packed participants data - * - * @return -1 if proposing a new security group was unsuccessful, otherwise returns 0. -*/ -__attribute__((eosio_wasm_import)) -int64_t remove_security_group_participants(const char* data, uint32_t datalen); - -/** - * Check if the specified accounts are all in the active security group. - * - * @param data - the buffer containing the packed participants. - * @param datalen - size of the packed participants - * - * @return Returns true if the specified accounts are all in the active security group. -*/ -__attribute__((eosio_wasm_import)) -bool in_active_security_group(const char* data, uint32_t datalen); - -/** - * Gets the active security group - * - * @param[out] data - the output buffer containing the packed security group. - * @param datalen - size of the `data` buffer - * - * @return Returns the size required in the buffer (if the buffer is too small, nothing is written). - * -*/ -__attribute__((eosio_wasm_import)) -uint32_t get_active_security_group(char* data, uint32_t datalen); - -#ifdef __cplusplus -} -#endif diff --git a/libraries/eosiolib/contracts/eosio/instant_finality.hpp b/libraries/eosiolib/contracts/eosio/instant_finality.hpp new file mode 100644 index 0000000000..f1bd97a3fa --- /dev/null +++ b/libraries/eosiolib/contracts/eosio/instant_finality.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include "../../capi/eosio/types.h" +#include "../../core/eosio/crypto_bls_ext.hpp" + +#include +#include + +/** + * @defgroup instant_finality Instant_finality + * @ingroup instant_finality + * @ingroup contracts + * @brief Defines C++ Instant Finality API + */ + +namespace eosio { + namespace internal_use_do_not_use { + extern "C" { + __attribute__((eosio_wasm_import)) + void set_finalizers( uint64_t packed_finalizer_format, const char* data, uint32_t len ); + } // extern "C" + } //internal_use_do_not_use + + struct finalizer_authority { + std::string description; + uint64_t weight = 0; // weight that this finalizer's vote has for meeting threshold + std::vector public_key; // Affine little endian non-montgomery g1 + + EOSLIB_SERIALIZE(finalizer_authority, (description)(weight)(public_key)); + }; + struct finalizer_policy { + uint64_t threshold = 0; + std::vector finalizers; + + EOSLIB_SERIALIZE(finalizer_policy, (threshold)(finalizers)); + }; + +/** + * Submits a finalizer policy change to Instant Finality + * + * @param finalizer_policy - finalizer policy to be set + */ + inline void set_finalizers( const finalizer_policy& finalizer_policy ) { + for (const auto& finalizer : finalizer_policy.finalizers) + eosio::check(finalizer.public_key.size() == sizeof(bls_g1), "public key has a wrong size" ); + auto packed = eosio::pack(finalizer_policy); + // 0 is packed format, currently only 0 is supported + internal_use_do_not_use::set_finalizers(0, packed.data(), packed.size()); + } + +} //eosio diff --git a/libraries/eosiolib/contracts/eosio/security_group.hpp b/libraries/eosiolib/contracts/eosio/security_group.hpp deleted file mode 100644 index b5575b8835..0000000000 --- a/libraries/eosiolib/contracts/eosio/security_group.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once -#include -#include "../../core/eosio/name.hpp" -#include "../../core/eosio/serialize.hpp" - -namespace eosio { - -namespace internal_use_do_not_use { -extern "C" { -__attribute__((eosio_wasm_import)) int64_t add_security_group_participants(const char* data, uint32_t datalen); - -__attribute__((eosio_wasm_import)) int64_t remove_security_group_participants(const char* data, uint32_t datalen); - -__attribute__((eosio_wasm_import)) bool in_active_security_group(const char* data, uint32_t datalen); - -__attribute__((eosio_wasm_import)) uint32_t get_active_security_group(char* data, uint32_t datalen); -} -} // namespace internal_use_do_not_use - -/** - * @defgroup security_group Security Group - * @ingroup contracts - * @brief Defines C++ security group API - */ - -struct security_group { - uint32_t version; - std::set participants; - CDT_REFLECT(version, participants); -}; - -/** - * Propose new participants to the security group. - * - * @ingroup security_group - * @param participants - the participants. - * - * @return -1 if proposing a new security group was unsuccessful, otherwise returns 0. - */ -inline int64_t add_security_group_participants(const std::set& participants) { - auto packed_participants = eosio::pack( participants ); - return internal_use_do_not_use::add_security_group_participants( packed_participants.data(), packed_participants.size() ); -} - -/** - * Propose to remove participants from the security group. - *å - * @ingroup security_group - * @param participants - the participants. - *å - * @return -1 if proposing a new security group was unsuccessful, otherwise returns 0. - */ -inline int64_t remove_security_group_participants(const std::set& participants){ - auto packed_participants = eosio::pack( participants ); - return internal_use_do_not_use::remove_security_group_participants( packed_participants.data(), packed_participants.size() ); -} - -/** - * Check if the specified accounts are all in the active security group. - * - * @ingroup security_group - * @param participants - the participants. - * - * @return Returns true if the specified accounts are all in the active security group. - */ -inline bool in_active_security_group(const std::set& participants){ - auto packed_participants = eosio::pack( participants ); - return internal_use_do_not_use::in_active_security_group( packed_participants.data(), packed_participants.size() ); -} - -/** - * Gets the active security group - * - * @ingroup security_group - * @param[out] packed_security_group - the buffer containing the packed security_group. - * - * @return Returns the size required in the buffer (if the buffer is too small, nothing is written). - * - */ -inline security_group get_active_security_group() { - size_t buffer_size = internal_use_do_not_use::get_active_security_group(0, 0); - std::vector buffer(buffer_size); - internal_use_do_not_use::get_active_security_group(buffer.data(), buffer_size); - return eosio::unpack(buffer); -} -} // namespace eosio \ No newline at end of file diff --git a/libraries/eosiolib/contracts/eosio/singleton.hpp b/libraries/eosiolib/contracts/eosio/singleton.hpp index 17f70aa08c..a9625b43ef 100644 --- a/libraries/eosiolib/contracts/eosio/singleton.hpp +++ b/libraries/eosiolib/contracts/eosio/singleton.hpp @@ -62,7 +62,7 @@ namespace eosio { * @return true - if exists * @return false - otherwise */ - bool exists() { + bool exists() const { return _t.find( pk_value ) != _t.end(); } @@ -72,7 +72,7 @@ namespace eosio { * @brief Get the value stored inside the singleton table * @return T - The value stored */ - T get() { + T get() const { auto itr = _t.find( pk_value ); eosio::check( itr != _t.end(), "singleton does not exist" ); return itr->value; @@ -84,7 +84,7 @@ namespace eosio { * @param def - The default value to be returned in case the data doesn't exist * @return T - The value stored */ - T get_or_default( const T& def = T() ) { + T get_or_default( const T& def = T() ) const { auto itr = _t.find( pk_value ); return itr != _t.end() ? itr->value : def; } diff --git a/libraries/eosiolib/core/eosio/base64.hpp b/libraries/eosiolib/core/eosio/base64.hpp new file mode 100644 index 0000000000..0f800e8eee --- /dev/null +++ b/libraries/eosiolib/core/eosio/base64.hpp @@ -0,0 +1,59 @@ +/* + base64 encoding and decoding with C++. + More information at + https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp + https://github.com/ReneNyffenegger/cpp-base64 + + Version: 2.rc.09 (release candidate) + + Copyright (C) 2004-2017, 2020-2022 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +*/ + +#include "check.hpp" + +#include +#include + +namespace eosio { + +namespace detail { +std::string base64_encode(unsigned char const*, size_t len, bool url = false); +std::string base64_decode(std::string_view s, bool remove_linebreaks = false, bool url = false); + +} // detail namespace + +inline std::string base64_encode(std::string_view enc) { + return detail::base64_encode(reinterpret_cast(enc.data()), enc.size(), false); +} +inline std::string base64_decode(std::string_view encoded_string) { + return detail::base64_decode(encoded_string, false); +} +inline std::string base64url_encode(std::string_view enc) { + return detail::base64_encode(reinterpret_cast(enc.data()), enc.size(), true); +} +inline std::string base64url_decode(std::string_view encoded_string) { + return detail::base64_decode(encoded_string, true, true); +} + +} // namespace eosio diff --git a/libraries/eosiolib/core/eosio/check.hpp b/libraries/eosiolib/core/eosio/check.hpp index 2d5d560e57..243707a576 100644 --- a/libraries/eosiolib/core/eosio/check.hpp +++ b/libraries/eosiolib/core/eosio/check.hpp @@ -22,6 +22,15 @@ namespace eosio { } } + + /** + * Return codes returned by host functions + */ + enum return_code : int32_t { + failure = -1, + success = 0 + }; + /** * @defgroup system System * @ingroup core diff --git a/libraries/eosiolib/core/eosio/crypto.hpp b/libraries/eosiolib/core/eosio/crypto.hpp index b7ca46a980..58053e2097 100644 --- a/libraries/eosiolib/core/eosio/crypto.hpp +++ b/libraries/eosiolib/core/eosio/crypto.hpp @@ -317,6 +317,23 @@ namespace eosio { */ eosio::checksum160 ripemd160( const char* data, uint32_t length ); + /** + * Verifies an RSA signature using SHA-256 hashing. + * + * @ingroup crypto + * @param message - Pointer to the message data to be verified + * @param message_len - Length of the message data + * @param signature - RSA signature to verify + * @param exponent - RSA public key exponent + * @param modulus - RSA public key modulus + * @return bool - `true` if the signature is valid, `false` otherwise + */ + bool verify_rsa_sha256_sig( const void* message, + uint32_t message_len, + std::string_view signature, + std::string_view exponent, + std::string_view modulus); + /** * Calculates the public key used for a given signature on a given digest. * diff --git a/libraries/eosiolib/core/eosio/crypto_bls_ext.hpp b/libraries/eosiolib/core/eosio/crypto_bls_ext.hpp new file mode 100644 index 0000000000..87236f7a92 --- /dev/null +++ b/libraries/eosiolib/core/eosio/crypto_bls_ext.hpp @@ -0,0 +1,502 @@ +#pragma once + +#include "crypto.hpp" + +#include "fixed_bytes.hpp" +#include "varint.hpp" +#include "serialize.hpp" +#include "base64.hpp" + +#include +#include +#include + +namespace bls12_381 { +class sha256 { +public: + sha256(): m_blocklen(0), m_bitlen(0) { + m_state[0] = 0x6a09e667; + m_state[1] = 0xbb67ae85; + m_state[2] = 0x3c6ef372; + m_state[3] = 0xa54ff53a; + m_state[4] = 0x510e527f; + m_state[5] = 0x9b05688c; + m_state[6] = 0x1f83d9ab; + m_state[7] = 0x5be0cd19; + } + void update(const uint8_t * data, size_t length) { + for(size_t i = 0 ; i < length ; i++) { + m_data[m_blocklen++] = data[i]; + if (m_blocklen == 64) { + transform(); + + // End of the block + m_bitlen += 512; + m_blocklen = 0; + } + } + } + inline void update(const char* data, size_t length) { + update(reinterpret_cast(data), length); + } + inline void update(const std::string &data) { + update(reinterpret_cast(data.data()), data.size()); + } + std::array digest() { + std::array hash; + + pad(); + revert(hash); + + return hash; + } + void digest(uint8_t* dst) { + std::array* phash = reinterpret_cast*>(dst); + + pad(); + revert(*phash); + } + + //static string toString(const array& digest); + +private: + uint8_t m_data[64]; + uint32_t m_blocklen; + uint64_t m_bitlen; + uint32_t m_state[8]; //A, B, C, D, E, F, G, H + + static constexpr std::array K = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5, + 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3, + 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc, + 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7, + 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13, + 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3, + 0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5, + 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208, + 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + }; + + static uint32_t rotr(uint32_t x, uint32_t n) { + return (x >> n) | (x << (32 - n)); + } + static uint32_t choose(uint32_t e, uint32_t f, uint32_t g) { + return (e & f) ^ (~e & g); + } + static uint32_t majority(uint32_t a, uint32_t b, uint32_t c) { + return (a & (b | c)) | (b & c); + } + static uint32_t sig0(uint32_t x) { + return sha256::rotr(x, 7) ^ sha256::rotr(x, 18) ^ (x >> 3); + } + static uint32_t sig1(uint32_t x) { + return sha256::rotr(x, 17) ^ sha256::rotr(x, 19) ^ (x >> 10); + } + void transform() { + uint32_t maj, xorA, ch, xorE, sum, newA, newE, m[64]; + uint32_t state[8]; + + for(uint8_t i = 0, j = 0; i < 16; i++, j += 4) { + // Split data in 32 bit blocks for the 16 first words + m[i] = (m_data[j] << 24) | (m_data[j + 1] << 16) | (m_data[j + 2] << 8) | (m_data[j + 3]); + } + + for(uint8_t k = 16 ; k < 64; k++) { + // Remaining 48 blocks + m[k] = sha256::sig1(m[k - 2]) + m[k - 7] + sha256::sig0(m[k - 15]) + m[k - 16]; + } + + for(uint8_t i = 0 ; i < 8 ; i++) { + state[i] = m_state[i]; + } + + for(uint8_t i = 0; i < 64; i++) { + maj = sha256::majority(state[0], state[1], state[2]); + xorA = sha256::rotr(state[0], 2) ^ sha256::rotr(state[0], 13) ^ sha256::rotr(state[0], 22); + + ch = choose(state[4], state[5], state[6]); + + xorE = sha256::rotr(state[4], 6) ^ sha256::rotr(state[4], 11) ^ sha256::rotr(state[4], 25); + + sum = m[i] + K[i] + state[7] + ch + xorE; + newA = xorA + maj + sum; + newE = state[3] + sum; + + state[7] = state[6]; + state[6] = state[5]; + state[5] = state[4]; + state[4] = newE; + state[3] = state[2]; + state[2] = state[1]; + state[1] = state[0]; + state[0] = newA; + } + + for(uint8_t i = 0 ; i < 8 ; i++) { + m_state[i] += state[i]; + } + } + void pad() { + uint64_t i = m_blocklen; + uint8_t end = m_blocklen < 56 ? 56 : 64; + + m_data[i++] = 0x80; // Append a bit 1 + while(i < end) { + m_data[i++] = 0x00; // Pad with zeros + } + + if(m_blocklen >= 56) { + transform(); + memset(m_data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + m_bitlen += m_blocklen * 8; + m_data[63] = m_bitlen; + m_data[62] = m_bitlen >> 8; + m_data[61] = m_bitlen >> 16; + m_data[60] = m_bitlen >> 24; + m_data[59] = m_bitlen >> 32; + m_data[58] = m_bitlen >> 40; + m_data[57] = m_bitlen >> 48; + m_data[56] = m_bitlen >> 56; + transform(); + } + void revert(std::array& hash) { + // SHA uses big endian byte ordering + // Revert all bytes + for(uint8_t i = 0 ; i < 4 ; i++) { + for(uint8_t j = 0 ; j < 8 ; j++) { + hash[i + (j * 4)] = (m_state[j] >> (24 - i * 8)) & 0x000000ff; + } + } + } +}; +} // namespace bls12_381 + +namespace eosio { + + namespace internal_use_do_not_use { + extern "C" { + __attribute__((eosio_wasm_import)) + int32_t bls_g1_add(const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* res, uint32_t res_len); + + __attribute__((eosio_wasm_import)) + int32_t bls_g2_add(const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* res, uint32_t res_len); + + __attribute__((eosio_wasm_import)) + int32_t bls_g1_weighted_sum(const char* points, uint32_t points_len, const char* scalars, uint32_t scalars_len, uint32_t n, char* res, uint32_t res_len); + + __attribute__((eosio_wasm_import)) + int32_t bls_g2_weighted_sum(const char* points, uint32_t points_len, const char* scalars, uint32_t scalars_len, uint32_t n, char* res, uint32_t res_len); + + __attribute__((eosio_wasm_import)) + int32_t bls_pairing(const char* g1_points, uint32_t g1_points_len, const char* g2_points, uint32_t g2_points_len, uint32_t n, char* res, uint32_t res_len); + + __attribute__((eosio_wasm_import)) + int32_t bls_g1_map(const char* e, uint32_t e_len, char* res, uint32_t res_len); + + __attribute__((eosio_wasm_import)) + int32_t bls_g2_map(const char* e, uint32_t e_len, char* res, uint32_t res_len); + + __attribute__((eosio_wasm_import)) + int32_t bls_fp_mod(const char* s, uint32_t s_len, char* res, uint32_t res_len); + + __attribute__((eosio_wasm_import)) + int32_t bls_fp_mul(const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* res, uint32_t res_len); + + __attribute__((eosio_wasm_import)) + int32_t bls_fp_exp(const char* base, uint32_t base_len, const char* exp, uint32_t exp_len, char* res, uint32_t res_len); + } + } + + using bls_scalar = std::array; + using bls_fp = std::array; + using bls_s = std::array; + using bls_fp2 = std::array; + using bls_g1 = std::array; // affine little-endian + using bls_g2 = std::array; // affine little-endian + using bls_gt = std::array; // group fp12 + + inline int32_t bls_g1_add(const bls_g1& op1, const bls_g1& op2, bls_g1& res) { + return internal_use_do_not_use::bls_g1_add( + op1.data(), op1.size(), + op2.data(), op2.size(), + res.data(), res.size() + ); + } + + inline int32_t bls_g2_add(const bls_g2& op1, const bls_g2& op2, bls_g2& res) { + return internal_use_do_not_use::bls_g2_add( + op1.data(), op1.size(), + op2.data(), op2.size(), + res.data(), res.size() + ); + } + + inline int32_t bls_g1_weighted_sum(const bls_g1 g1_points[], const bls_scalar scalars[], uint32_t num, bls_g1& res) { + if (num == 0) + return return_code::failure; + return internal_use_do_not_use::bls_g1_weighted_sum( + g1_points[0].data(), num * g1_points[0].size(), + scalars[0].data(), num * scalars[0].size(), + num, + res.data(), res.size() + ); + } + + inline int32_t bls_g2_weighted_sum(const bls_g2 g2_points[], const bls_scalar scalars[], uint32_t num, bls_g2& res) { + if (num == 0) + return return_code::failure; + return internal_use_do_not_use::bls_g2_weighted_sum( + g2_points[0].data(), num * g2_points[0].size(), + scalars[0].data(), num * scalars[0].size(), + num, + res.data(), res.size() + ); + } + + inline int32_t bls_pairing(const bls_g1 g1_points[], const bls_g2 g2_points[], const uint32_t num, bls_gt& res) { + if (num == 0) + return return_code::failure; + return internal_use_do_not_use::bls_pairing( + g1_points[0].data(), num * g1_points[0].size(), + g2_points[0].data(), num * g2_points[0].size(), + num, + res.data(), res.size() + ); + } + + inline int32_t bls_g1_map(const bls_fp& e, bls_g1& res) { + return internal_use_do_not_use::bls_g1_map( + e.data(), e.size(), + res.data(), res.size() + ); + } + + inline int32_t bls_g2_map(const bls_fp2& e, bls_g2& res) { + return internal_use_do_not_use::bls_g2_map( + e[0].data(), 2 * e[0].size(), + res.data(), res.size() + ); + } + + inline int32_t bls_fp_mod(const bls_s& s, bls_fp& res) { + return internal_use_do_not_use::bls_fp_mod( + s.data(), s.size(), + res.data(), res.size() + ); + } + + inline int32_t bls_fp_mul(const bls_fp& op1, const bls_fp& op2, bls_fp& res) { + return internal_use_do_not_use::bls_fp_mul( + op1.data(), op1.size(), + op2.data(), op2.size(), + res.data(), res.size() + ); + } + + inline int32_t bls_fp_exp(const bls_fp& base, const bls_s& exp, bls_fp& res) { + return internal_use_do_not_use::bls_fp_exp( + base.data(), base.size(), + exp.data(), exp.size(), + res.data(), res.size() + ); + } + +namespace detail { + const inline std::string bls_public_key_prefix = "PUB_BLS_"; + constexpr inline uint32_t bls_checksum_size = sizeof(uint32_t); + const inline std::string bls_signature_prefix = "SIG_BLS_"; + + template + std::string bls_type_to_base64url(const T& g1) { + std::array g1_with_checksum; + auto it = std::copy(g1.begin(), g1.end(), g1_with_checksum.begin()); + + auto csum = ripemd160(g1.data(), g1.size()).extract_as_byte_array(); + std::copy(reinterpret_cast(csum.data()), + reinterpret_cast(csum.data())+bls_checksum_size, + it); + + return Prefix + eosio::base64url_encode({g1_with_checksum.data(), g1_with_checksum.size()}); + } + + template + T bls_base64url_to_type(const char* data, size_t size) { + eosio::check(size > Prefix.size(), "encoded base64 key is too short"); + eosio::check(0 == memcmp(data, Prefix.data(), Prefix.size()), "base64 encoded type must begin from corresponding prefix"); + + std::string decoded = eosio::base64url_decode({data+Prefix.size(), size - Prefix.size()}); + T ret; + eosio::check(decoded.size() == ret.size() + bls_checksum_size, "decoded size " + std::to_string(decoded.size()) + + " doesn't match structure size " + std::to_string(ret.size()) + + " + checksum " + std::to_string(bls_checksum_size)); + + auto it = decoded.end(); + std::advance(it, -bls_checksum_size); + std::copy(decoded.begin(), it, ret.begin()); + + auto csum = ripemd160(ret.data(), ret.size()).extract_as_byte_array(); + eosio::check(0 == memcmp(&*it, csum.data(), bls_checksum_size), "checksum of structure doesn't match"); + + return ret; + } + + const inline std::string CIPHERSUITE_ID = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_"; // basic DST + const inline std::string POP_CIPHERSUITE_ID = "BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; // proof of possession DST + + // g1::one().negate().toAffineBytesLE(), 96 bytes + const inline std::vector G1_ONE_NEG = {0xbb, 0xc6, 0x22, 0xdb, 0xa, 0xf0, 0x3a, 0xfb, 0xef, 0x1a, 0x7a, 0xf9, + 0x3f, 0xe8, 0x55, 0x6c, 0x58, 0xac, 0x1b, 0x17, 0x3f, 0x3a, 0x4e, 0xa1, + 0x5, 0xb9, 0x74, 0x97, 0x4f, 0x8c, 0x68, 0xc3, 0xf, 0xac, 0xa9, 0x4f, + 0x8c, 0x63, 0x95, 0x26, 0x94, 0xd7, 0x97, 0x31, 0xa7, 0xd3, 0xf1, 0x17, + 0xca, 0xc2, 0x39, 0xb9, 0xd6, 0xdc, 0x54, 0xad, 0x1b, 0x75, 0xcb, 0xe, + 0xba, 0x38, 0x6f, 0x4e, 0x36, 0x42, 0xac, 0xca, 0xd5, 0xb9, 0x55, 0x66, + 0xc9, 0x7, 0xb5, 0x1d, 0xef, 0x6a, 0x81, 0x67, 0xf2, 0x21, 0x2e, 0xcf, + 0xc8, 0x76, 0x7d, 0xaa, 0xa8, 0x45, 0xd5, 0x55, 0x68, 0x1d, 0x4d, 0x11}; + + // fp12::one().toBytesLE(), 576 bytes + const inline std::vector GT_ONE = []{ std::vector r(576, 0); r[0] = 1; return r; }(); + + // Construct an extensible-output function based on SHA256 + inline void xmd_sh256( + char *buf, + int buf_len, + const char *in, + int in_len, + const char *dst, + int dst_len + ) { + const unsigned int SHA256HashSize = 32; + const unsigned int SHA256_Message_Block_Size = 64; + const unsigned ell = (buf_len + SHA256HashSize - 1) / SHA256HashSize; + if (buf_len < 0 || ell > 255 || dst_len > 255) { + return; + } + const uint8_t Z_pad[SHA256_Message_Block_Size] = { 0, }; + const uint8_t l_i_b_0_str[] = { + static_cast(buf_len >> 8), + static_cast(buf_len & 0xff), + 0, + static_cast(dst_len) + }; + const uint8_t *dstlen_str = l_i_b_0_str + 3; + uint8_t b_0[SHA256HashSize]; + bls12_381::sha256 sha; + sha.update(Z_pad, SHA256_Message_Block_Size); + sha.update(in, in_len); + sha.update(l_i_b_0_str, 3); + sha.update(dst, dst_len); + sha.update(dstlen_str, 1); + sha.digest(b_0); + uint8_t b_i[SHA256HashSize + 1] = { 0, }; + for (unsigned i = 1; i <= ell; ++i) { + for (unsigned j = 0; j < SHA256HashSize; ++j) { + b_i[j] = b_0[j] ^ b_i[j]; + } + b_i[SHA256HashSize] = i; + bls12_381::sha256 s; + s.update(b_i, SHA256HashSize + 1); + s.update(dst, dst_len); + s.update(dstlen_str, 1); + s.digest(b_i); + const int rem_after = buf_len - i * SHA256HashSize; + const int copy_len = SHA256HashSize + (rem_after < 0 ? rem_after : 0); + memcpy(buf + (i - 1) * SHA256HashSize, b_i, copy_len); + } + } + + inline bls_s scalar_fromBE(const bls_s& in) { + bls_s out; + constexpr size_t last_index = sizeof(out) - 1; + for(size_t i = 0; i <= last_index; ++i) + { + out[i] = in[last_index - i]; + } + return out; + } + + inline void g2_fromMessage(std::span msg, const std::string& dst, bls_g2& res) { + + std::array buf; + xmd_sh256(buf.data()->data(), sizeof(buf), msg.data(), msg.size(), dst.data(), dst.length()); + + bls_s k; + bls_fp2 t; + bls_g2 p, q; + + k = scalar_fromBE(buf[0]); + bls_fp_mod(k, t[0]); + k = scalar_fromBE(buf[1]); + bls_fp_mod(k, t[1]); + + bls_g2_map(t, p); + + k = scalar_fromBE(buf[2]); + bls_fp_mod(k, t[0]); + k = scalar_fromBE(buf[3]); + bls_fp_mod(k, t[1]); + + bls_g2_map(t, q); + bls_g2_add(p, q, res); + } +} // namespace detail + + inline std::string encode_g1_to_bls_public_key(const bls_g1& g1) { + return detail::bls_type_to_base64url(g1); + } + inline bls_g1 decode_bls_public_key_to_g1(std::string_view public_key) { + return detail::bls_base64url_to_type(public_key.data(), public_key.size()); + } + inline std::string encode_g2_to_bls_signature(const bls_g2& g2) { + return detail::bls_type_to_base64url(g2); + } + inline bls_g2 decode_bls_signature_to_g2(std::string_view public_key) { + return detail::bls_base64url_to_type(public_key.data(), public_key.size()); + } + + // pubkey and signature are assumed to be in RAW affine little-endian bytes + inline bool bls_pop_verify(const bls_g1& pubkey, const bls_g2& signature_proof) { + using namespace detail; + + bls_g1 g1_points[2] = {0}; + bls_g2 g2_points[2] = {0}; + + std::memcpy(g1_points[0].data(), G1_ONE_NEG.data(), G1_ONE_NEG.size()); + std::memcpy(g2_points[0].data(), signature_proof.data(), signature_proof.size()); + + std::memcpy(g1_points[1].data(), pubkey.data(), pubkey.size()); + g2_fromMessage(pubkey, POP_CIPHERSUITE_ID, g2_points[1]); + + bls_gt r; + bls_pairing(g1_points, g2_points, 2, r); + + return 0 == std::memcmp(r.data(), GT_ONE.data(), GT_ONE.size()); + } + + // pubkey and signature are assumed to be in RAW affine little-endian bytes + inline bool bls_signature_verify(const bls_g1& pubkey, const bls_g2& signature_proof, const std::string& msg) { + bls_g1 g1_points[2]; + bls_g2 g2_points[2]; + + std::memcpy(g1_points[0].data(), detail::G1_ONE_NEG.data(), detail::G1_ONE_NEG.size()); + std::memcpy(g2_points[0].data(), signature_proof.data(), signature_proof.size()); + + std::memcpy(g1_points[1].data(), pubkey.data(), pubkey.size()); + detail::g2_fromMessage(msg, detail::CIPHERSUITE_ID, g2_points[1]); + + bls_gt r; + bls_pairing(g1_points, g2_points, 2, r); + + return 0 == std::memcmp(r.data(), detail::GT_ONE.data(), detail::GT_ONE.size()); + } +} + diff --git a/libraries/eosiolib/crypto.cpp b/libraries/eosiolib/crypto.cpp index bc96fbd0db..3acdf903a4 100644 --- a/libraries/eosiolib/crypto.cpp +++ b/libraries/eosiolib/crypto.cpp @@ -35,6 +35,12 @@ extern "C" { __attribute__((eosio_wasm_import)) void ripemd160( const char* data, uint32_t length, capi_checksum160* hash ); + __attribute__((eosio_wasm_import)) + int32_t verify_rsa_sha256_sig( const void* message, uint32_t message_len, + const char* signature, uint32_t signature_len, + const char* exponent, uint32_t exponent_len, + const char* modulus, uint32_t modulus_len); + __attribute__((eosio_wasm_import)) int recover_key( const capi_checksum256* digest, const char* sig, size_t siglen, char* pub, size_t publen ); @@ -90,6 +96,18 @@ namespace eosio { return {hash.hash}; } + bool verify_rsa_sha256_sig( const void* message, + uint32_t message_len, + std::string_view signature, + std::string_view exponent, + std::string_view modulus) { + return ::verify_rsa_sha256_sig( + message, message_len, + signature.data(), signature.size(), + exponent.data(), exponent.size(), + modulus.data(), modulus.size()); + } + eosio::public_key recover_key( const eosio::checksum256& digest, const eosio::signature& sig ) { auto digest_data = digest.extract_as_byte_array(); diff --git a/libraries/meta_refl/include/bluegrass/meta/function_traits.hpp b/libraries/meta_refl/include/bluegrass/meta/function_traits.hpp index f02731bbfc..915a7b0cfc 100644 --- a/libraries/meta_refl/include/bluegrass/meta/function_traits.hpp +++ b/libraries/meta_refl/include/bluegrass/meta/function_traits.hpp @@ -65,11 +65,6 @@ namespace bluegrass { namespace meta { template constexpr bool pass_type() { return true; } - template - constexpr bool is_callable_impl(...) { - return false; - } - template struct wrapper_t { using type = T; diff --git a/libraries/meta_refl/modules/catch2_install.cmake.in b/libraries/meta_refl/modules/catch2_install.cmake.in index eeca0099e3..cf9b641422 100644 --- a/libraries/meta_refl/modules/catch2_install.cmake.in +++ b/libraries/meta_refl/modules/catch2_install.cmake.in @@ -16,7 +16,7 @@ if (NOT ${found_project}) ExternalProject_Add( catch2_external_proj GIT_REPOSITORY "https://github.com/catchorg/Catch2" - GIT_TAG "v2.12.2" + GIT_TAG "v2.13.10" SOURCE_DIR @CATCH2_DIRECTORY@/catch2 BINARY_DIR @CATCH2_DIRECTORY@/catch2 BUILD_ALWAYS 0 diff --git a/libraries/native/intrinsics.cpp b/libraries/native/intrinsics.cpp index 0d5a80786a..9d847b25fc 100644 --- a/libraries/native/intrinsics.cpp +++ b/libraries/native/intrinsics.cpp @@ -229,6 +229,12 @@ extern "C" { int32_t db_end_i64(capi_name code, uint64_t scope, capi_name table) { return intrinsics::get().call(code, scope, table); } + int32_t verify_rsa_sha256_sig( const void* message, uint32_t message_len, + const char* signature, uint32_t signature_len, + const char* exponent, uint32_t exponent_len, + const char* modulus, uint32_t modulus_len){ + return intrinsics::get().call(message, message_len, signature, signature_len, exponent, exponent_len, modulus, modulus_len); + } void assert_recover_key( const capi_checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen ) { return intrinsics::get().call(digest, sig, siglen, pub, publen); } @@ -890,23 +896,11 @@ extern "C" { } #pragma clang diagnostic pop - int64_t add_security_group_participants(const char* data, uint32_t datalen) { - return intrinsics::get().call(data, datalen); - } - - int64_t remove_security_group_participants(const char* data, uint32_t datalen){ - return intrinsics::get().call(data, datalen); - } - - bool in_active_security_group(const char* data, uint32_t datalen){ - return intrinsics::get().call(data, datalen); - } - - uint32_t get_active_security_group(char* data, uint32_t datalen){ - return intrinsics::get().call(data, datalen); + void set_finalizers(uint64_t packed_finalizer_format, const char* data, uint32_t len) { + intrinsics::get().call(packed_finalizer_format, data, len); } - -} + +} // extern "C" int32_t blake2_f( uint32_t rounds, const char* state, uint32_t state_len, const char* msg, uint32_t msg_len, const char* t0_offset, uint32_t t0_len, const char* t1_offset, uint32_t t1_len, int32_t final, char* result, uint32_t result_len) { @@ -935,4 +929,54 @@ int32_t mod_exp( const char* base, uint32_t base_len, const char* exp, uint32_t void sha3( const char* data, uint32_t data_len, char* hash, uint32_t hash_len, int32_t keccak ) { intrinsics::get().call(data, data_len, hash, hash_len, keccak); -} \ No newline at end of file +} + +int32_t bls_g1_add(const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* res, uint32_t res_len) +{ + return intrinsics::get().call(op1, op1_len, op2, op2_len, res, res_len); +} + +int32_t bls_g2_add(const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* res, uint32_t res_len) +{ + return intrinsics::get().call(op1, op1_len, op2, op2_len, res, res_len); +} + +int32_t bls_g1_weighted_sum(const char* points, uint32_t points_len, const char* scalars, uint32_t scalars_len, uint32_t n, char* res, uint32_t res_len) +{ + return intrinsics::get().call(points, points_len, scalars, scalars_len, n, res, res_len); +} + +int32_t bls_g2_weighted_sum(const char* points, uint32_t points_len, const char* scalars, uint32_t scalars_len, uint32_t n, char* res, uint32_t res_len) +{ + return intrinsics::get().call(points, points_len, scalars, scalars_len, n, res, res_len); +} + +int32_t bls_pairing(const char* g1_points, uint32_t g1_points_len, const char* g2_points, uint32_t g2_points_len, uint32_t n, char* res, uint32_t res_len) +{ + return intrinsics::get().call(g1_points, g1_points_len, g1_points, g1_points_len, n, res, res_len); +} + +int32_t bls_g1_map(const char* e, uint32_t e_len, char* res, uint32_t res_len) +{ + return intrinsics::get().call(e, e_len, res, res_len); +} + +int32_t bls_g2_map(const char* e, uint32_t e_len, char* res, uint32_t res_len) +{ + return intrinsics::get().call(e, e_len, res, res_len); +} + +int32_t bls_fp_mod(const char* s, uint32_t s_len, char* res, uint32_t res_len) +{ + return intrinsics::get().call(s, s_len, res, res_len); +} + +int32_t bls_fp_mul(const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* res, uint32_t res_len) +{ + return intrinsics::get().call(op1, op1_len, op2, op2_len, res, res_len); +} + +int32_t bls_fp_exp(const char* base, uint32_t base_len, const char* exp, uint32_t exp_len, char* res, uint32_t res_len) +{ + return intrinsics::get().call(base, base_len, exp, exp_len, res, res_len); +} diff --git a/libraries/native/native/eosio/intrinsics_def.hpp b/libraries/native/native/eosio/intrinsics_def.hpp index 4dd728117e..f4aee787ea 100644 --- a/libraries/native/native/eosio/intrinsics_def.hpp +++ b/libraries/native/native/eosio/intrinsics_def.hpp @@ -4,14 +4,15 @@ #include #include #include +#include #include +#include #include #include #include #include #include #include -#include #include #include @@ -162,19 +163,25 @@ intrinsic_macro(cancel_deferred) \ intrinsic_macro(get_context_free_data) \ intrinsic_macro(get_sender) \ intrinsic_macro(set_action_return_value) \ -intrinsic_macro(add_security_group_participants) \ -intrinsic_macro(remove_security_group_participants) \ -intrinsic_macro(in_active_security_group) \ -intrinsic_macro(get_active_security_group) \ intrinsic_macro(blake2_f) \ intrinsic_macro(sha3) \ intrinsic_macro(k1_recover) \ intrinsic_macro(alt_bn128_add) \ intrinsic_macro(alt_bn128_mul) \ intrinsic_macro(alt_bn128_pair) \ -intrinsic_macro(mod_exp) - - +intrinsic_macro(mod_exp) \ +intrinsic_macro(bls_g1_add) \ +intrinsic_macro(bls_g2_add) \ +intrinsic_macro(bls_g1_weighted_sum) \ +intrinsic_macro(bls_g2_weighted_sum) \ +intrinsic_macro(bls_pairing) \ +intrinsic_macro(bls_g1_map) \ +intrinsic_macro(bls_g2_map) \ +intrinsic_macro(bls_fp_mod) \ +intrinsic_macro(bls_fp_mul) \ +intrinsic_macro(bls_fp_exp) \ +intrinsic_macro(set_finalizers) \ +intrinsic_macro(verify_rsa_sha256_sig) #define CREATE_ENUM(name) \ name, diff --git a/modules/TestsExternalProject.txt b/modules/TestsExternalProject.txt index f22a55564e..8b6d479df3 100644 --- a/modules/TestsExternalProject.txt +++ b/modules/TestsExternalProject.txt @@ -16,9 +16,9 @@ ExternalProject_Add( ) -find_package(leap QUIET) +find_package(spring QUIET) -if (leap_FOUND) +if (spring_FOUND) if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(TEST_BUILD_TYPE "Debug") else() @@ -40,5 +40,5 @@ if (leap_FOUND) BUILD_ALWAYS 1 ) else() - message(STATUS "leap package not found, skipping building integration tests") + message(STATUS "spring package not found, skipping building integration tests") endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2590f7345b..e699d9afd3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,6 +4,7 @@ macro(add_unit_test TEST_NAME) endmacro() add_unit_test( asset_tests ) +add_unit_test( base64_tests ) add_unit_test( binary_extension_tests ) add_unit_test( crt_tests ) add_unit_test( crypto_tests ) @@ -28,7 +29,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unit/version_tests.sh ${CMAKE_BINARY_ add_test(NAME version_tests COMMAND ${CMAKE_BINARY_DIR}/tests/unit/version_tests.sh "${VERSION_FULL}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST version_tests PROPERTY LABELS unit_tests) -if (leap_FOUND) +if (spring_FOUND) add_test(integration_tests ${CMAKE_BINARY_DIR}/tests/integration/integration_tests) set_property(TEST integration_tests PROPERTY LABELS integration_tests) endif() diff --git a/tests/integration/CMakeLists.txt b/tests/integration/CMakeLists.txt index cd2b3fec8b..be19469465 100644 --- a/tests/integration/CMakeLists.txt +++ b/tests/integration/CMakeLists.txt @@ -1,10 +1,10 @@ cmake_minimum_required( VERSION 3.5 ) -set(EOSIO_VERSION_MIN "3.1") +set(EOSIO_VERSION_MIN "1.0") set(EOSIO_VERSION_SOFT_MAX "5.0") #set(EOSIO_VERSION_HARD_MAX "") -find_package(leap) +find_package(spring) find_path(GMP_INCLUDE_DIR NAMES gmp.h) find_library(GMP_LIBRARY gmp) @@ -17,11 +17,11 @@ EOSIO_CHECK_VERSION(VERSION_OUTPUT "${EOSIO_VERSION}" "${EOSIO_VERSION_HARD_MAX}" VERSION_MATCH_ERROR_MSG) if(VERSION_OUTPUT STREQUAL "MATCH") - message(STATUS "Using Leap version ${EOSIO_VERSION}") + message(STATUS "Using Spring version ${EOSIO_VERSION}") elseif(VERSION_OUTPUT STREQUAL "WARN") - message(WARNING "Using Leap version ${EOSIO_VERSION} even though it exceeds the maximum supported version of ${EOSIO_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use Leap version ${EOSIO_VERSION_SOFT_MAX}.x") + message(WARNING "Using Spring version ${EOSIO_VERSION} even though it exceeds the maximum supported version of ${EOSIO_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use Spring version ${EOSIO_VERSION_SOFT_MAX}.x") else() # INVALID OR MISMATCH - message(FATAL_ERROR "Found Leap version ${EOSIO_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use Leap version ${EOSIO_VERSION_SOFT_MAX}.x") + message(FATAL_ERROR "Found Spring version ${EOSIO_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use Spring version ${EOSIO_VERSION_SOFT_MAX}.x") endif(VERSION_OUTPUT STREQUAL "MATCH") diff --git a/tests/integration/bls_tests.cpp b/tests/integration/bls_tests.cpp new file mode 100644 index 0000000000..b2880a6609 --- /dev/null +++ b/tests/integration/bls_tests.cpp @@ -0,0 +1,143 @@ +#include +#include +#include + +#include + +#include + +using namespace eosio; +using namespace eosio::testing; +using namespace eosio::chain; +using namespace eosio::testing; +using namespace fc; + +using mvo = fc::mutable_variant_object; + +struct bls_primitives_tester : tester { + bls_primitives_tester() { + create_accounts( { "test"_n } ); + produce_block(); + + set_code( "eosio"_n, contracts::bls_primitives_test_wasm() ); + set_abi( "eosio"_n, contracts::bls_primitives_test_abi().data() ); + + produce_blocks(); + } +}; + +BOOST_AUTO_TEST_SUITE(bls_primitives_tests) + +BOOST_FIXTURE_TEST_CASE( g1_add_test, bls_primitives_tester ) try { + push_action("eosio"_n, "testg1add"_n, "test"_n, mvo() + ("op1", "aa83970268d80b50a68535d920954bd993217b9114cbe255e5c0b64e748c5683b6518071552148ec555cdb8fed0f07001e76e62761e8d828a74b81f216a0c5ebeb923550cafd110512cec20e33ec9b272c0ff2b88215953945153fc926691506") + ("op2", "e810c1d6ac7cbae0157a0fc958ef607c33e03dee20e72a97ae72de0dd9a0ef20d768ab4b659429255b87feda0be194062a77cd664976e6560b33c921d5968c19a5d5ae9e38c909690975c084c0a4e82481b01e4023b83d6a8ddcb9d38892f50f") + ("res", "145cae227562a69bbf270b8ec8d1783bed4ad0fd43e9c81ac5caa7d3e7feaa3acda07d6033ece1f7f0649d6b75009a03e83ab8f9b44f94c4ab762611266b7a530ce05092ad38b7554a95caa2b63ad0969a902d69f34531dbccf8a4f2e12cf60d")); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( g2_add_test, bls_primitives_tester ) try { + push_action("eosio"_n, "testg2add"_n, "test"_n, mvo() + ("op1", "a75a447bc0dd806bcdaee2cb429498193e409a4d370dfe0e9605c5a9ec4a09c0314c0321f2f918b72e5f37cf10ea7e0b69ac1a7fb3200e63e5cef9929cd2d9afde2fb957989e610c5b44649af8649d968baa0424b873b501be32c66ef040240b469127753f17ca28a072c2151b69d51fecff1ed0f4786b4e6fd4e52ec72f95ef73cf19fc2d6a28267bdf11a262b403110c2e901fb32d0e900082e4934a20c1c06c262533488fd7f9f47e4e2fde102fe98fb48344de25712d5e2e2887bc04d207") + ("op2", "11cc3115ad08c43ed0b7fc3945ca83c69d0a6663f05b25373ea3fdff14c722a7fddd7a1b4f1cf44290e1c480f50b6208419f6a208ea48a48cef5a345a35c052cf0db4a76c719eb90a5829a8f606e99c807a6ae71493f079c364d57f02cba7c124f344978bb539bea7c448eb96ccea9b6c7b7d2495212b88227fc269ac88391f4a6d23e2d47d4fe47e63f8e709b61450644ba13c08e29770bc397da41466cb26c9fa7a1ffd9b5dd5c51c3ddbfb88412998e41f72e63b7972dfd856b9f11530c01") + ("res", "d9458632a7cfcf59e72cf6d1ad70ec8d65d9e81edd0da77c2b10ec4d2a4169f1b0ac46419796d3ed6ef66b34eb76651288d916a5e5b44e75cc849ecd257a223398f92683f2318bf5fe7aa2b5d45e97dad6c415dac4b9cdc1c72071a4c9845c15096b203deb2e071d3856983cb26a101eb193cbfe914000ade94a62339b2e418c4a53578fb177af1986cc9dee3ce9ff0f9598925cb7e5a29af31404fa8cd9c22e17eb1a44b6b461dd9b7dc4d384ad60b82d94e431a389a244b1724a5441ac6009")); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( g1_weighted_sum_test, bls_primitives_tester ) try { + push_action("eosio"_n, "testg1wsum"_n, "test"_n, mvo() + ("points", "7a63674c35f9f2be4f0ec092110b82fad24a283316a846d960843b9a6a8a98bfdabd7e897b7da774fbbb05d7ad95fb18940a5f7a7345e1821e0203e156d677e88445385bc0779d25f51b772be3c3a6ba0b09b2533a8ee66053b2f3c853994112e74a97324685e515c86d44ff5a3ef5218e53c6f29e7df49a546c79cd1fb9d14e63f68aaf6b2df1f6f56e6250fdd6f20dcc36499a5aea69f4c77a18774eccf8460e77ab6b0236ce2d85083faeacf0f3378a3dcc95e1d3b0ae282b9bbec1ecee1793e63ca4730ec63df496546c07094e848625610a514d99dd0a6dd9f58d15c4e4ed5aca65025562177ebd0a4c2c3ae8139d24be936dd5dbec6a54897ba2a98a68a9c43ea3199695896789c958bc289a7275550b5670a351b262c10166a48baa161f841df4255408abb7186f78647422313fbe3a0a35699a487dd71482b76b8adc20622f44bb32e04a78b98e4f2cd42f16a6d35ec2463a484906dbb655969b900a15cc8a47694b1961bd4b2e9f074afd79e4c04344d31dd8fcd56d5147a9a47712") + ("scalars", "2be3984dc7a5c9e6172df42c905be929ce5bb29d9aa31a03f3ed8816e7d1265a0669a674fef9254f0efffd3e89c30f1f05587472251d362e1acea03a76918d137b322778b8188c1bf68c36ef8e0ce933290c67f981611c13a286e42235f89855e49966a4e9ad8c64122f4f5e720986193e59771fa91aef113d8739642bdd6613") + ("num", 4) + ("res", "25038aea2d2d1c15dad2fa4c6e31162d1b79ca1b1bca608190a05dea451701e9fc95a8c441a25083df7fa56d54eae51241a8c9489719b9cc35852ce3d7e04b5ada5c65f45d1818f80ea161264b70ab6fa86e694691281b8110000d209aea5c17")); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( g2_weighted_sum_test, bls_primitives_tester ) try { + push_action("eosio"_n, "testg2wsum"_n, "test"_n, mvo() + ("points", "556524e3e80fcf448c0befd659ad744c409cdd1111291a81949324a02688999ab88e6ccb3e9dcecf57ccfe9aa7ada21540ba5407c0700ce81578bcee892ed385dd1ed476c465fe48cea2dd7e37784d8ae795fba842ce0f88baa76857ec1c7c137163beed84ff2c6a159d486d10c7128b2cbb6f10c547d202d0f6e68fb43a9a6a18a01823c4e70b5dc25d38b9c33d4916510de467f10922f3b284855c4accc816f542fe74fd0b331b1884dac6918d3c38860b0725809a19b6101e5d3942b9f40eee6901e17a0c50187e6385767b7d1e54eaacbb3c1939e2e995ec79569dd0200583a937891035475e1e5a733a0446f7063e77f9d564c60dfc6dc25572369bf7fe51b2607f73fd0fa9eee9d27b127a81c63bbd7f08dd64237d082e9735018d96024c56d32b55e991e84f39c6ffc0d56ef17307e82fc200df9259f83b7bdae719124f7151d855b8f51f703e087ea1540900c4eba1592de051db895689aeb5233dec52ccb74f93acc8fc14bcde4413a14dceb0ec386623021ddf9ad1fce429e1780c5a6877b00b17af384fd49b7077434387672218967f4a7647174162c07e99d9007380be10a7bef367181ba886a0e40c160a4b36548826c30710ea8238b0c37ec06e331fe1d3aaf1b5a73ae0880794d0c0a9623b8498d9bbd4754e1a8c1e2346091fec42aaeddc40f2ae06456e8ad9059c61db437089a855af3d1bc2a6d68e9c01474bdbaabfa185a58dba9808f8e0b20a3c51c51c5bca629aa061dfa5ff238a43e1e90242df403635869743c723276c0eca711c6c91b94a65310b6b869ee556179ed113a2b406a52de2fe54f61f4589f510924b2e3f8b14ead1541af2e1cc9dd35a91f6cd4bbc02c58a844d9e4906a106197b8ab39a539561aeecd265762bcf5106344ae2fe0a62c7af1bbc846e9b39ebe38a046461d7c0c4901caddb0fd7c70b86246d53bf3124af629596f6367e86f3456cc954e3581bfea600b6d2818259332fedeb88ece673626ffd4d5935d0310e5cf2462055d5fa4b6cc4531f11cf0722c8647dbfc7364c9b2e24e0066ef5b0e3497ce38537a7230e02f7edc2f53e980f") + ("scalars", "e5a6afde5d144ed43bd1742b7ec7f5385a7d392f65465927e37afe7b9f0a9e368449cf52e36ca432b096f8562c98f318216d21a426b2d51f0a4db8fcafcd687326b548cd973f30d4fc47d79d853ec94239c620229ea0632b2570a1f8df08fe1ce323ef2cad610917a13d1157e25fac05ef6bafaa68e8ce265594d207a5d13c1e") + ("num", 4) + ("res", "889d8b750987cbce4aa4b872b29f22011752354e672b24ad4b229ca575ce14a8c081366db5cfd0f7a85ff68559bd4216b3cecfb6a2618a29c6c95b17147d083f28cc1fae5959fd7de74d986e7fd543ce1060cbdd8d4ae136910d8a15a1b3ee16d955657630d5f50aae107d13aa0c46040616e2d3018e5d07f9551e2a4c34565c9b59b8fd7751e025f473772120b4a511946e09fc93dcf9732399244c1fbb864fa09c2dd5d29543e794e64b6e1a2df39289245ff4b65dff0357a6621d151e4514")); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( pairing_test, bls_primitives_tester ) try { + push_action("eosio"_n, "testpairing"_n, "test"_n, mvo() + ("g1_points", "af7d28fa69e9ff7cf98da7614f02faf91f8ae2888d522db1a225724394bedd8547ae93cb07b41f5f21092846c6c2950e43328c2e6aaa18cf735a703f4ee43a60658167b9c1bf895ddbc898dae5269a335699c595aa9dc4137103d5480320270f756a4c35700b847a02d4933be43e508139affb438b7bcf547debcf9904f1056d197ec8484283e2f194430e16443d250f0b4734d5380cac631d6287e2b45a6a12fb5fea3eed96a7b2cd3bac9a532e4bb6176b1e792964444798e5bf151e14c314277fa052e05911619c457335e708633aca11239a33686e56dd949e6f50e5fe79f1d069bbb01822566f992299184ddc06d08c662a5d2b37668c7821bef5177ff4df977799dc81ae15d0444be9a54db2195d41e316f7ebdb7d879f8f7b355cb416137401a36684f0ccbce51fd4d8b32f45d81f2c33bc95687ed777e7fcb181367e163d94356c96d239f193dabf01616d13936ba746ed9a64578a5a4b191238fe8472e4135525afcac4ed818c13e518864ce82de26a6bb1066b9c0771c021716603") + ("g2_points", "5528fc322669dcf2757583835b5ba5cc84f629db47e1d5e3ec78523fff567ec26100b7977ba038586c9e465abbaeb603554afef9cfe21ac33847b1d11796088cc6b18c7544355da3f996ddb0c0a15c8b1eeba2ec3a5cc8c7b4a8ecc7131e4609582cc42caa57f68017f95af50757bfc0d3c4d4327d1d40012af8f664da428f1984bf17c26d43b6fd65a8ce6c3d039d03f1247385a3f565108de722d4e08b0e9d23bba036646668167bdd41709ebe8bf5aadbd88ccc2af0c6d5940531c9fd50053e786ffe9011554db15fc7e130ea07cd254f21a86911fe758517274f96b89cb67e30c104186c4a6cb0d92cb82e39260245b68e74bdb828992697a1957be0564a9863f56eaf36bb5fc4d0869468b6ad4e36a1e7c550303c80c4ca0cbae773b309a61c6d4d6a4d2f17a4424c1987d294f195275581c8b8f88b7ce7fec5bc67e7bfd58bb747f39aa4dbc77d79cd18dd09142b10a45d49abc8fd544281f02a0e045062b72b25ead1a376e4f705ac83ad2385c84a8fd914d2f6a71d7eeb7126d677001013a0df759ff906a09fe4a3da307dd6cc17ee1fd72af8f7d953662be427cda2985cb1073563bbea492d9e6a96ca8a05ca5d45d349cb3e2f09cff6022a9916324eaa4fe5c543d46cafe5f82e81c5baddc2cc58100b03a20c2feaeed58cbd63019b8e3586d14193470d4ee9c1a0fc5e0a736e1ba94d7ad20ead3a3dacc4b2f3530ad751daffa944be4cb1969b3d2595058007d28d49e2fdebab68607c119b77d766785ed9e209582c737fce93b6ad0d4d795f86415238e0d3b70b9d8954d6a20ce85e7128588a849c505d5d2c81ff63bf12ea3ad52a316316ce49b2014dfbc486c9934dccb98db06089c03dc8f76ad70323ada12fe7e5b9f552c5b6cc073f72409a6e44f6634ca58bed30649b9840f177ea0039932f81574ea22b6da18b702f0e367f633e41d2b585d5166669f4c48d389f003eeecf06b5aa119d0df46de26adcb938d362e4410fdaa990a6fc4c2eca0f7bffee724789a0a47ba1b531bb4a3c95c129585ba5c9a6fe978a6915f4afedeb710ef6a55f153a5b21f943de6531680d") + ("res", "01cc207c7c76c65afc059d073106d545705af7c4e4ed78e6169c599bae1c9bf6358d5a2cdfeeae389cc64436dfe7b7192c733fe9e2d105c0eaec21589d8bb5ecd5c71a5fee083af47a1cbc3af2df8a13603a78956c39f55fd0663ed482846a047280f87426ecde4c535c0d30bdf4b95ff5aff45782129ee6c7a0fa20a632bc98e95bfb663685eb2443e4b1f518c40f00502303b3db49be61f36ef6af46b9097c83835a864ae6337ef07e40df617af1aacea98c0d75e96a104d41a3617e7a4f05fc1cdcec57ea40a0237ff387a5d9130b34c92cb57a3450080bbaa2f6f9e895851b05c05eec03abd2d5083c81c402a500d2bec4895cf0f58a9953e43ee9039a38ae73cc3ec325fa636777e1f597b69a2b6a62bd49fba5b163bc03ce73f277f818fad1c6681fa59be891c2baf85b6a5e908d96b6a6c4cf3d53b3de23fdade91b3dde7199648aca0fce1d2307253bf57b054a4c4dc276034f8d57017cddc0a84975c643f9ea808652f2cefea32f767fe8e6df58a837c47c3136ced7107e7dbd9711399605212e6a1b8da806a12636076f7da0629ca8173f0411ba2a1050d1bca61994e28f69f274ec94e016a3ba6f9a6b06cd17f570928b5e4b8c75a5d62a0a67bd54249702923b440355db775599ea7be7cd3c6d88ab8da7694e43352837b0080814880a1460bc61fae141d36f961db8393313f74a65c3eabcc38793b84062999364bb0c36a415445ec4318b59c16e850260a53e7aaaf72bcaa568b57b69b552bf827c3e1c116565122322d6c26e14354fd96dc4bb1161ede0ee36efeeae1a5503")); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( g1_map_test, bls_primitives_tester ) try { + push_action("eosio"_n, "testg1map"_n, "test"_n, mvo() + ("e", "6de1c03023f2b4e454559b97266ebc1f96cd5510c4f48e2acafbe73a536a1477f2c8d1c9b5f6615d01968ea59ef4fd07") + ("res", "2c7390d4bfbe0ccbaae9699aab5458d62f6d1aa91938b0ab0717249ad89209cb14ee8ed764a8952415382dbbfdef2312d5b2988b1ed7e6907d73ef2335cba7f9263b63003effa44ab8d6805d6ed0f08d87919230f0cb45d9ec35b2e0615d920f")); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( g2_map_test, bls_primitives_tester ) try { + push_action("eosio"_n, "testg2map"_n, "test"_n, mvo() + ("e", "b4108d552274d175fd4e52dd766ff396a4f365c102e0ef7b4d266f220ec67eefab48ac15d1db0d98ba31cda435616e0bdeb51952b044ce0f64b5d42199d9560ed0175f3d2c58af07909d29db4480c1b417dfbf7f1af274648adb54b029e38f08") + ("res", "f74a6a357dc6a1fb33344f60898ab9eb29c68170727136b26d943249fbbd9393bd893846ea0d43250d4fd37737e49f1463d11827561e80cda0f6ead2cd3c84d4be6d99d61fa4cbc41cce534af2cf3d1b3fc31ccecc1259cfc7530a93c58e801951454f38f693d2d763e0f993c202151d873eefec3e90507cea6232cb3c0061f254a2f4b5872098b23362763a79d6c004333e0e02ad077c8a3683d63827becf20c88a9b7a63bbac739bc3a4f659d119df2f5853e371a25c803fc8301c393e7804")); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( fp_mul_test, bls_primitives_tester ) try { + push_action("eosio"_n, "testfpmul"_n, "test"_n, mvo() + ("op1", "AAAAFFFFFFFFFEB9FFFF53B1FEFFAB1E24F6B0F6A0D23067BF1285F3844B7764D7AC4B43B6A71B4B9AE67F39EA11011A") + ("op2", "AAAAFFFFFFFFFEB9FFFF53B1FEFFAB1E24F6B0F6A0D23067BF1285F3844B7764D7AC4B43B6A71B4B9AE67F39EA11011A") + ("res", "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( fp_exp_test, bls_primitives_tester ) try { + push_action("eosio"_n, "testfpexp"_n, "test"_n, mvo() + ("base", "AAAAFFFFFFFFFEB9FFFF53B1FEFFAB1E24F6B0F6A0D23067BF1285F3844B7764D7AC4B43B6A71B4B9AE67F39EA11011A") + ("exp", "AAAAFFFFFFFFFEB9FFFF53B1FEFFAB1E24F6B0F6A0D23067BF1285F3844B7764D7AC4B43B6A71B4B9AE67F39EA11011A00000000000000000000000000000000") + ("res", "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( base64_test, bls_primitives_tester ) try { + push_action("eosio"_n, "g1baseb4enc"_n, "test"_n, mvo() + ("g1", "4783d417e555ba2fe4a6a9068e3c212bc43d5c895a83dc15bfdcbb65357c4caafbf6a6884c36a41c68587a77caba3f1105feb50023b4806b003c913c3ecca1ede21ff4cf322576520571977958ec1f6b8d483ae505a1eb93675ecf856ae0dc0e") + ("base64", "PUB_BLS_R4PUF-VVui_kpqkGjjwhK8Q9XIlag9wVv9y7ZTV8TKr79qaITDakHGhYenfKuj8RBf61ACO0gGsAPJE8Psyh7eIf9M8yJXZSBXGXeVjsH2uNSDrlBaHrk2dez4Vq4NwOf9VEMA")); + push_action("eosio"_n, "sigbaseb4enc"_n, "test"_n, mvo() + ("g2", "ddb6db1f52a1eb191dfa57656645689fbd08e76170f08c9674c20c243c71bda00054d06862623083abe2a738da032000f1d2784eefacb8696a48f185ecc225f2b0cc26d3e59d84cb6bafba976785002446cd2921cb954daa124058a368ba270ef6e7a57e41f3c651f2ca6e70982330b5ab3acc65887f24e9f5c63d3550d2c6fa643fd6ea061c7e24ecdc41a8c55850089ab3cf40b0d986d283d065f1e7b66047008596d721db450b0e8b8eada95a09ca258a651d0d19b4651e2b38cbae308218") + ("base64", "SIG_BLS_3bbbH1Kh6xkd-ldlZkVon70I52Fw8IyWdMIMJDxxvaAAVNBoYmIwg6vipzjaAyAA8dJ4Tu-suGlqSPGF7MIl8rDMJtPlnYTLa6-6l2eFACRGzSkhy5VNqhJAWKNouicO9uelfkHzxlHyym5wmCMwtas6zGWIfyTp9cY9NVDSxvpkP9bqBhx-JOzcQajFWFAImrPPQLDZhtKD0GXx57ZgRwCFltch20ULDouOralaCcolimUdDRm0ZR4rOMuuMIIYOJG0NA")); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( sig_verify_test, bls_primitives_tester ) try { + // assumes signed message of std::vector msg = {51, 23, 56, 93, 212, 129, 128, 27, 251, 12, 42, 129, 210, 9, 34, 98}; + // vector seed(32, 0x30); array sk = secret_key(seed); g1 pk = g1::one().scale(sk).affine(); string pk_hex = to_hex(pk.toAffineBytesLE()); + // g2 sig = sign(sk, msg); string sig_hex = to_hex(sig.toAffineBytesLE()); + push_action("eosio"_n, "verifyraw"_n, "test"_n, mvo() + ("pk", "c27efc440ed89d739ff80f1c7178d4672d5f71e8c8926a85785d0f84074e79c1662c522fdbd6fcaebd640d816dea6c0dc36c5d7e7a297afc960369e306d845fcad0e5fe2a88c0d3bbe854d4f9e3e6365c9c1003662f0e81b35fd9c6a11d0a10c") + ("sig", "e13a38c18dfad440a9af8d720bfb9ce0f388a25a5789a8cdc34b87204fe29db5cc16658a5d9f4fa4a7cc16b8ef8d2d0d1a5984e6b69ca228692f1920e9340f149024b4d856711656f11bb1e0c7d081e5bb80692638a9bace2d8f4d796b4887129c59fbb7901997cbbb681f709291a45315979f55b719dfc8757d3a878cf01e4a48a0e6647b837d0ea8aea5d41e121b0dd37fa20007aef4f51740d846cc8d6ab151dbd88964e7d19890a500d5537be81b881451b75f928a66f546441d45028603")); + + // bls_private_key sk = bls_private_key(seed_1); + // bls_public_key pk = sk.get_public_key(); + // std::string msg = "this is a message string"; + // std::vector msg_v(msg.begin(), msg.end()); + // bls_signature signature = sk.sign(msg_v); + // pk.to_string(); + // signature.to_string(); + push_action("eosio"_n, "verify"_n, "test"_n, mvo() + ("pk", "PUB_BLS_sS66EwY8bNx7vkDn3mKhwPhhqa1V6STN1QSb6bWOIFBTloF5zt5b55r9y7uQMiQGrvt6XOZO3CpEgthlba7R7qz7Qob2YcD5EX3Ng_rUUdMBsjEJRuXNWICPe0QbKAoCQOw9vw") + ("sig", "SIG_BLS_07NCCTekrxhDFurhRhl3b8m4T-xmTixSl63TYcee_xJONi2_qy9-8o5vyetMefsL4hhDMfy1yIeHERqxUvGguRBBncpabp84b3P2bNpY18A-PVs7qKFqlld1gEUqt-cDOcwkyUe6HqqFXR5wtXoSHE4lHauV3CzR0lD91gnr2c49aUQPAC7SD-ZcnZyahwURje-Db26zhTXIO1WWIx6vwKnZUuvZEbzYrijjBQKeZsqp0eoAzjrByx9gOmN2d_AR9PhRvg") + ("msg", "this is a message string")); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( sig_pop_verify_test, bls_primitives_tester ) try { + push_action("eosio"_n, "popverifyraw"_n, "test"_n, mvo() + ("pk", "3b08e73bbda9c3eff597fc60fbb1bd8c81af3659024f62829082438ef52a02a71f99658087ea58108e12543c08980a0f1950c7f3085ab4b49e3137e8d35adfcbed616dd37cd011435e940a74f53f99ab1d1fd220a089d4e8517df0267ecb0802") + ("sig", "3a1e5689abddbd0ed54c48c88dcef7ac9bba70abdd7a8e965fb807a188cfc8a7e21ca5c9ecc58df7681d158cc6aced13d50bbe35a5aa7848c32a290b096e1f7a61b2817660bd6e6d5686180a1c00716d47ee996ced081fdb6c4417d6cc8dbd06f26f037331c1b4703e94454374ba04e71fb7571159299b9020c124e9ecee777c2b5c16a51ca883b716082fdf2e6c150551a82eaca5efaf761053d6998a439cc696366fe82eb93f19aac34893610698b37d11f0d608fdc1befc50a7e565ea4813")); + + push_action("eosio"_n, "popverify"_n, "test"_n, mvo() + ("pk", "PUB_BLS_82P3oM1u0IEv64u9i4vSzvg1-QDl4Fb2n50Mp8Sk7Fr1Tz0MJypzL39nSd5VPFgFC9WqrjopRbBm1Pf0RkP018fo1k2rXaJY7Wtzd9RKlE8PoQ6XhDm4PyZlIupQg_gOuiMhcg") + ("sig", "SIG_BLS_RrwvP79LxfahskX-ceZpbgrJ1aUkSSIzE2sMFj0twuhK8QwjcGMvT2tZ_-QMHvAV83tWZYOs7SEvoyteCKGD_Tk6YySkw1HONgvVeNWM8ZwuNgonOHkegNNPIXSIvWMTczfkg2lEtEh-ngBa5t9-4CvZ6aOjg29XPVvu6dimzHix-9E0M53YkWZ-gW5GDkkOLoN2FMxjXaELmhuI64xSeSlcWLFfZa6TMVTctBFWsHDXm1ZMkURoB83dokKHEi4OQTbJtg")); +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/integration/contracts.hpp.in b/tests/integration/contracts.hpp.in index 6fea3a3d08..b4be50e834 100644 --- a/tests/integration/contracts.hpp.in +++ b/tests/integration/contracts.hpp.in @@ -23,6 +23,12 @@ namespace eosio::testing { static std::vector crypto_primitives_test_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/crypto_primitives_tests.wasm"); } static std::vector crypto_primitives_test_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/crypto_primitives_tests.abi"); } + static std::vector bls_primitives_test_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/bls_primitives_tests.wasm"); } + static std::vector bls_primitives_test_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/bls_primitives_tests.abi"); } + + static std::vector instant_finality_test_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/instant_finality_tests.wasm"); } + static std::vector instant_finality_test_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/instant_finality_tests.abi"); } + static std::vector get_code_hash_write_test_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/get_code_hash_write.wasm"); } static std::vector get_code_hash_write_test_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/get_code_hash_write.abi"); } static std::vector get_code_hash_read_test_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/get_code_hash_read.wasm"); } diff --git a/tests/integration/instant_finality_tests.cpp b/tests/integration/instant_finality_tests.cpp new file mode 100644 index 0000000000..f79ef71125 --- /dev/null +++ b/tests/integration/instant_finality_tests.cpp @@ -0,0 +1,55 @@ +#include + +#include +#include +#include + +#include + +using namespace eosio; +using namespace eosio::testing; +using namespace fc; + +using mvo = fc::mutable_variant_object; + +BOOST_AUTO_TEST_SUITE(instant_finality_tests) + +BOOST_FIXTURE_TEST_CASE(instant_finality_test, tester) try { + create_accounts( { "test"_n } ); + produce_block(); + + set_code( config::system_account_name, contracts::instant_finality_test_wasm() ); + set_abi( config::system_account_name, contracts::instant_finality_test_abi().data() ); + + produce_block(); + + push_action(config::system_account_name, "setfinalizer"_n, "test"_n, mvo() + ("finalizer_policy", mvo()("threshold", 1) + ("finalizers", std::vector{mvo() + ("description", "test_desc") + ("weight", 1) + ("public_key", "744beeb74c9d1debc318fe847f73b822ae905dff6351c3144f59c22515fe251625158acefea2adff1e37f6f509d83919df639de8074967e4bd756444f52cbeed0e9b363a6820e3f4716ce4282d43aa685f137a5a5be293840de7a0b915f12b08")}))); + signed_block_ptr cur_block = produce_block(); + fc::variant pretty_output; + abi_serializer::to_variant( *cur_block, pretty_output, get_resolver(), fc::microseconds::maximum() ); + std::cout << fc::json::to_string(pretty_output, fc::time_point::now() + abi_serializer_max_time) << std::endl; + + std::string output_json = fc::json::to_pretty_string(pretty_output); + BOOST_TEST(output_json.find("finality_extension") != std::string::npos); + BOOST_TEST(output_json.find("\"generation\": 2") != std::string::npos); + BOOST_TEST(output_json.find("\"threshold\": 1") != std::string::npos); + BOOST_TEST(output_json.find("\"description\": \"test_desc\"") != std::string::npos); + BOOST_TEST(output_json.find("\"weight\": 1") != std::string::npos); + BOOST_TEST(output_json.find("PUB_BLS_dEvut0ydHevDGP6Ef3O4Iq6QXf9jUcMUT1nCJRX-JRYlFYrO_qKt_x439vUJ2DkZ32Od6AdJZ-S9dWRE9Sy-7Q6bNjpoIOP0cWzkKC1DqmhfE3paW-KThA3noLkV8SsILcfxpQ") != std::string::npos); + + // testing wrong public key size + BOOST_CHECK_THROW(push_action(config::system_account_name, "setfinalizer"_n, "test"_n, mvo() + ("finalizer_policy", mvo()("threshold", 1) + ("finalizers", std::vector{mvo() + ("description", "test_desc") + ("weight", 1) + ("public_key", std::vector{'a', 'b', 'c'})}))), fc::exception); + +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/integration/multi_index_tests.cpp b/tests/integration/multi_index_tests.cpp index c5420a77ff..919ced1194 100644 --- a/tests/integration/multi_index_tests.cpp +++ b/tests/integration/multi_index_tests.cpp @@ -18,7 +18,7 @@ using namespace eosio::testing; BOOST_AUTO_TEST_SUITE(multi_index_tests) -// this test is copy from leap test_api_multi_index +// this test is copied from Spring test_api_multi_index BOOST_FIXTURE_TEST_CASE(main_multi_index_tests, TESTER) { try { produce_blocks(1); create_account( "testapi"_n ); diff --git a/tests/toolchain/compile-fail/host_functions_tests.cpp b/tests/toolchain/compile-fail/host_functions_tests.cpp index 27068436e7..06fdcc98f7 100644 --- a/tests/toolchain/compile-fail/host_functions_tests.cpp +++ b/tests/toolchain/compile-fail/host_functions_tests.cpp @@ -8,6 +8,7 @@ set_blockchain_parameters_packed : yes set_parameters_packed : yes set_privileged : yes send_deferred : yes +set_finalizers : yes */ #include diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index d5a6eeab10..450c3ed4d0 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -5,7 +5,6 @@ include( CDTMacros ) macro(add_cdt_unit_test TEST_NAME) add_native_executable(${TEST_NAME} ${TEST_NAME}.cpp) - target_compile_options(${TEST_NAME} PRIVATE -fno-cfl-aa) if(CMAKE_BUILD_TYPE STREQUAL "Release") target_compile_options(${TEST_NAME} PRIVATE -O2) elseif(CMAKE_BUILD_TYPE STREQUAL "Debug") @@ -14,6 +13,7 @@ macro(add_cdt_unit_test TEST_NAME) endmacro() add_cdt_unit_test(asset_tests) +add_cdt_unit_test(base64_tests) add_cdt_unit_test(binary_extension_tests) add_cdt_unit_test(crt_tests) add_cdt_unit_test(crypto_tests) diff --git a/tests/unit/base64_tests.cpp b/tests/unit/base64_tests.cpp new file mode 100644 index 0000000000..7ec2f655d5 --- /dev/null +++ b/tests/unit/base64_tests.cpp @@ -0,0 +1,215 @@ +/** + * @file + * @copyright defined in eosio.cdt/LICENSE.txt + */ + +#include +#include + +using namespace eosio; +using namespace std::literals; + +EOSIO_TEST_BEGIN(base64enc) + auto input = "abc123$&()'?\xb4\xf5\x01\xfa~a"s; + auto expected_output = "YWJjMTIzJCYoKSc/tPUB+n5h"s; + + CHECK_EQUAL(expected_output, base64_encode(input)); +EOSIO_TEST_END + +// No trailing sequence of = added +EOSIO_TEST_BEGIN(base64urlenc) + auto input = "abc123$&()'?\xb4\xf5\x01\xfa~a"s; + auto expected_output = "YWJjMTIzJCYoKSc_tPUB-n5h"s; + + CHECK_EQUAL(expected_output, base64url_encode(input)); +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(base64dec) + auto input = "YWJjMTIzJCYoKSc/tPUB+n5h"s; + auto expected_output = "abc123$&()'?\xb4\xf5\x01\xfa~a"s; + + CHECK_EQUAL(expected_output, base64_decode(input)); +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(base64urldec) + auto input = "YWJjMTIzJCYoKSc_tPUB-n5h"s; + auto expected_output = "abc123$&()'?\xb4\xf5\x01\xfa~a"s; + + CHECK_EQUAL(expected_output, base64url_decode(input)); +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(base64dec_extraequals) + CHECK_ASSERT( "encountered non-base64 character", + ([](){ + base64_decode("YWJjMTIzJCYoKSc/tPUB+n5h========="s); + })); +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(base64dec_bad_stuff) + CHECK_ASSERT( "encountered non-base64 character", + ([](){ + base64_decode("YWJjMTIzJCYoKSc/tPU$B+n5h="s); + })); +EOSIO_TEST_END + +// `+` not valid in base64 url +EOSIO_TEST_BEGIN(base64urldec_plus_not_allowed) + CHECK_ASSERT( "encountered non-base64 character", + ([](){ + base64_decode("YWJjMTIzJCYoKSc+tPUB-n5h"s); + })); +EOSIO_TEST_END + +// `/` not valid in base64 url +EOSIO_TEST_BEGIN(base64urldec_slash_not_allowed) + CHECK_ASSERT( "encountered non-base64 character", + ([](){ + base64_decode("YWJjMTIzJCYoKSc/tPUB-n5h"s); + })); +EOSIO_TEST_END + +// trailing not allowed in base64 url +EOSIO_TEST_BEGIN(base64urldec_trailing_not_allowed) + CHECK_ASSERT( "encountered non-base64 character", + ([](){ + base64_decode("YWJjMTIzJCYoKSc_tPUB-n5h=="s); + })); +EOSIO_TEST_END + +// tests from https://github.com/ReneNyffenegger/cpp-base64/blob/master/test.cpp +EOSIO_TEST_BEGIN(base64_cpp_base64_tests) + // + // Note: this file must be encoded in UTF-8 + // for the following test, otherwise, the test item + // fails. + // + const std::string orig = + "René Nyffenegger\n" + "http://www.renenyffenegger.ch\n" + "passion for data\n"; + + std::string encoded = base64_encode({orig.c_str(), orig.length()}); + std::string decoded = base64_decode(encoded); + + CHECK_EQUAL(encoded, "UmVuw6kgTnlmZmVuZWdnZXIKaHR0cDovL3d3dy5yZW5lbnlmZmVuZWdnZXIuY2gKcGFzc2lvbiBmb3IgZGF0YQo="); + CHECK_EQUAL(decoded, orig); + + // Test all possibilites of fill bytes (none, one =, two ==) + // References calculated with: https://www.base64encode.org/ + + std::string rest0_original = "abc"; + std::string rest0_reference = "YWJj"; + + std::string rest0_encoded = base64_encode({rest0_original.c_str(),rest0_original.length()}); + std::string rest0_decoded = base64_decode(rest0_encoded); + + CHECK_EQUAL(rest0_decoded, rest0_original); + CHECK_EQUAL(rest0_reference, rest0_encoded); + + std::string rest1_original = "abcd"; + std::string rest1_reference = "YWJjZA=="; + + std::string rest1_encoded = base64_encode({rest1_original.c_str(), rest1_original.length()}); + std::string rest1_decoded = base64_decode(rest1_encoded); + + CHECK_EQUAL(rest1_decoded, rest1_original); + CHECK_EQUAL(rest1_reference, rest1_encoded); + + std::string rest2_original = "abcde"; + std::string rest2_reference = "YWJjZGU="; + + std::string rest2_encoded = base64_encode({rest2_original.c_str(),rest2_original.length()}); + std::string rest2_decoded = base64_decode(rest2_encoded); + + CHECK_EQUAL(rest2_decoded, rest2_original); + CHECK_EQUAL(rest2_reference, rest2_encoded); + + // -------------------------------------------------------------- + // + // Data that is 17 bytes long requires one padding byte when + // base-64 encoded. Such an encoded string could not correctly + // be decoded when encoded with «url semantics». This bug + // was discovered by https://github.com/kosniaz. The following + // test checks if this bug was fixed: + // + std::string a17_orig = "aaaaaaaaaaaaaaaaa"; + std::string a17_encoded = base64_encode(a17_orig); + std::string a17_encoded_url = base64url_encode(a17_orig); + + CHECK_EQUAL(a17_encoded, "YWFhYWFhYWFhYWFhYWFhYWE="); + CHECK_EQUAL(a17_encoded_url, "YWFhYWFhYWFhYWFhYWFhYWE"); + CHECK_EQUAL(base64_decode(a17_encoded_url), a17_orig); + CHECK_EQUAL(base64_decode(a17_encoded), a17_orig); + + // -------------------------------------------------------------- + + // characters 63 and 64 / URL encoding + + std::string s_6364 = "\x03" "\xef" "\xff" "\xf9"; + + std::string s_6364_encoded = base64_encode(s_6364); + std::string s_6364_encoded_url = base64url_encode(s_6364); + + CHECK_EQUAL(s_6364_encoded, "A+//+Q=="); + CHECK_EQUAL(s_6364_encoded_url, "A-__-Q"); + CHECK_EQUAL(base64_decode(s_6364_encoded), s_6364); + CHECK_EQUAL(base64url_decode(s_6364_encoded_url), s_6364); + + // ---------------------------------------------- + + std::string unpadded_input = "YWJjZGVmZw"; // Note the 'missing' "==" + std::string unpadded_decoded = base64_decode(unpadded_input); + CHECK_EQUAL(unpadded_decoded, "abcdefg"); + + unpadded_input = "YWJjZGU"; // Note the 'missing' "=" + unpadded_decoded = base64_decode(unpadded_input); + CHECK_EQUAL(unpadded_decoded, "abcde"); + + unpadded_input = ""; + unpadded_decoded = base64_decode(unpadded_input); + CHECK_EQUAL(unpadded_decoded, ""); + + unpadded_input = "YQ"; + unpadded_decoded = base64_decode(unpadded_input); + CHECK_EQUAL(unpadded_decoded, "a"); + + unpadded_input = "YWI"; + unpadded_decoded = base64_decode(unpadded_input); + CHECK_EQUAL(unpadded_decoded, "ab"); + + CHECK_ASSERT( "wrong encoded string size", + ([](){ + std::string not_null_terminated = std::string(1, 'a'); + base64_decode(not_null_terminated); + })); + // -------------------------------------------------------------- + // + // Test the string_view interface (which required C++17) + // + std::string_view sv_orig = "foobarbaz"; + std::string sv_encoded = base64_encode(sv_orig); + + CHECK_EQUAL(sv_encoded, "Zm9vYmFyYmF6"); + + std::string sv_decoded = base64_decode(sv_encoded); + + CHECK_EQUAL(sv_decoded, sv_orig); + +EOSIO_TEST_END + +int main(int argc, char* argv[]) { + bool verbose = false; + if( argc >= 2 && std::strcmp( argv[1], "-v" ) == 0 ) { + verbose = true; + } + silence_output(!verbose); + + EOSIO_TEST(base64enc); + EOSIO_TEST(base64urlenc); + EOSIO_TEST(base64dec); + EOSIO_TEST(base64urldec); + EOSIO_TEST(base64dec_extraequals); + EOSIO_TEST(base64dec_bad_stuff); + EOSIO_TEST(base64_cpp_base64_tests); + return has_failed(); +} diff --git a/tests/unit/test_contracts/CMakeLists.txt b/tests/unit/test_contracts/CMakeLists.txt index 48dc55e7e7..1cc1107231 100644 --- a/tests/unit/test_contracts/CMakeLists.txt +++ b/tests/unit/test_contracts/CMakeLists.txt @@ -7,6 +7,8 @@ add_contract(explicit_nested_tests explicit_nested_tests explicit_nested_tests.c add_contract(transfer_contract transfer_contract transfer.cpp) add_contract(minimal_tests minimal_tests minimal_tests.cpp) add_contract(crypto_primitives_tests crypto_primitives_tests crypto_primitives_tests.cpp) +add_contract(bls_primitives_tests bls_primitives_tests bls_primitives_tests.cpp) +add_contract(instant_finality_tests instant_finality_tests instant_finality_tests.cpp) add_contract(get_code_hash_tests get_code_hash_write get_code_hash_write.cpp) add_contract(get_code_hash_tests get_code_hash_read get_code_hash_read.cpp) add_contract(name_pk_tests name_pk_tests name_pk_tests.cpp) diff --git a/tests/unit/test_contracts/bls_primitives_tests.cpp b/tests/unit/test_contracts/bls_primitives_tests.cpp new file mode 100644 index 0000000000..fb866b50d0 --- /dev/null +++ b/tests/unit/test_contracts/bls_primitives_tests.cpp @@ -0,0 +1,150 @@ +#include +#include +#include +#include + +using namespace eosio; + +class [[eosio::contract]] bls_primitives_tests : public contract{ + public: + using contract::contract; + + [[eosio::action]] + void testg1add(const std::vector& op1, const std::vector& op2, const std::vector& res) { + check(op1.size() == std::tuple_size::value, "wrong op1 size passed"); + check(op2.size() == std::tuple_size::value, "wrong op2 size passed"); + bls_g1 r; + bls_g1_add(*reinterpret_cast(op1.data()), *reinterpret_cast(op2.data()), r); + check(std::equal(res.begin(), res.end(), r.begin()), "bls_g1_add test failed"); + } + + [[eosio::action]] + void testg2add(const std::vector& op1, const std::vector& op2, const std::vector& res) { + bls_g2 r; + bls_g2_add(*reinterpret_cast(op1.data()), *reinterpret_cast(op2.data()), r); + check(std::equal(res.begin(), res.end(), r.begin()), "bls_g2_add test failed"); + } + + [[eosio::action]] + void testg1wsum(const std::vector& points, const std::vector& scalars, const uint32_t num, const std::vector& res) + { + check(points.size() == std::tuple_size::value * num, "wrong points size passed"); + check(scalars.size() == std::tuple_size::value * num, "wrong scalars size passed"); + check(res.size() == std::tuple_size::value, "wrong res size passed"); + bls_g1 r; + int32_t error = bls_g1_weighted_sum( + reinterpret_cast(points.data()), + reinterpret_cast(scalars.data()), + num, + r + ); + check(std::equal(res.begin(), res.end(), r.begin()), "bls_g1_weighted_sum: Result does not match"); + } + + [[eosio::action]] + void testg2wsum(const std::vector& points, const std::vector& scalars, const uint32_t num, const std::vector& res) + { + check(points.size() == std::tuple_size::value * num, "wrong points size passed"); + check(scalars.size() == std::tuple_size::value * num, "wrong scalars size passed"); + check(res.size() == std::tuple_size::value, "wrong res size passed"); + bls_g2 r; + int32_t error = bls_g2_weighted_sum( + reinterpret_cast(points.data()), + reinterpret_cast(scalars.data()), + num, + r + ); + check(std::equal(res.begin(), res.end(), r.begin()), "bls_g2_weighted_sum: Result does not match"); + } + + [[eosio::action]] + void testpairing(const std::vector& g1_points, const std::vector& g2_points, const std::vector& res) { + auto num = g2_points.size()/sizeof(bls_g2); + check(g1_points.size()/sizeof(bls_g1) == num, "number of elements in g1_points and g2_points must be equal"); + bls_gt r; + bls_pairing(reinterpret_cast(g1_points.data()), reinterpret_cast(g2_points.data()), num, r); + check(std::equal(res.begin(), res.end(), r.begin()), "bls_pairing test failed"); + } + + [[eosio::action]] + void testg1map(const std::vector& e, const std::vector& res) { + bls_g1 r; + bls_g1_map(*reinterpret_cast(e.data()), r); + check(std::equal(res.begin(), res.end(), r.begin()), "bls_g1_map test failed"); + } + + [[eosio::action]] + void testg2map(const std::vector& e, const std::vector& res) { + bls_g2 r; + bls_g2_map(*reinterpret_cast(e.data()), r); + check(std::equal(res.begin(), res.end(), r.begin()), "bls_g2_map test failed"); + } + + [[eosio::action]] + void testfpmul(const std::vector& op1, const std::vector& op2, const std::vector& res) + { + bls_fp r; + int32_t error = bls_fp_mul( + *reinterpret_cast(op1.data()), + *reinterpret_cast(op2.data()), + r + ); + check(std::equal(res.begin(), res.end(), r.begin()), "bls_fp_mul: Result does not match"); + } + + [[eosio::action]] + void testfpexp(const std::vector& base, const std::vector& exp, const std::vector& res) + { + bls_fp r; + int32_t error = bls_fp_exp( + *reinterpret_cast(base.data()), + *reinterpret_cast(exp.data()), + r + ); + check(std::equal(res.begin(), res.end(), r.begin()), "bls_fp_exp: Result does not match"); + } + + [[eosio::action]] + void popverifyraw(const std::vector& pk, const std::vector& sig) { + check(pk.size() == std::tuple_size::value, "wrong public key size passed"); + check(sig.size() == std::tuple_size::value, "wrong signature size passed"); + check(bls_pop_verify(*reinterpret_cast(pk.data()), *reinterpret_cast(sig.data())), "raw pop verify failed"); + } + + [[eosio::action]] + void popverify(const std::string& pk, const std::string& sig) { + check(bls_pop_verify(decode_bls_public_key_to_g1(pk), decode_bls_signature_to_g2(sig)), "pop verify failed"); + } + + [[eosio::action]] + void g1baseb4enc(const std::vector& g1, const std::string& base64 ) { + check(g1.size() == std::tuple_size::value, "wrong g1 size passed"); + + check(encode_g1_to_bls_public_key(*reinterpret_cast(g1.data())) == base64, "g1 to base64 encoding doesn't match" ); + check(decode_bls_public_key_to_g1(base64) == *reinterpret_cast(g1.data()), "base64 to g1 decoding doesn't match" ); + } + + [[eosio::action]] + void sigbaseb4enc(const std::vector& g2, const std::string& base64) { + check(g2.size() == std::tuple_size::value, "wrong g2 size passed"); + check(encode_g2_to_bls_signature(*reinterpret_cast(g2.data())) == base64, "g2 to base64 encoding doesn't match" ); + check(decode_bls_signature_to_g2(base64) == *reinterpret_cast(g2.data()), "base64 to g2 decoding doesn't match" ); + } + + // caller of verify() must use this msg + std::vector msg = {51, 23, 56, 93, 212, 129, 128, 27, 251, 12, 42, 129, 210, 9, 34, 98}; + + [[eosio::action]] + void verifyraw(const std::vector& pk, const std::vector& sig) { + check(pk.size() == std::tuple_size::value, "wrong pk size passed"); + check(sig.size() == std::tuple_size::value, "wrong sig size passed"); + + std::string msg_str(msg.begin(), msg.end()); + check(bls_signature_verify(*reinterpret_cast(pk.data()), *reinterpret_cast(sig.data()), msg_str), "signature verify failed"); + } + + [[eosio::action]] + void verify(const std::string& pk, const std::string& sig, const std::string& msg) { + check(bls_signature_verify(decode_bls_public_key_to_g1(pk), decode_bls_signature_to_g2(sig), msg), "signature verify failed"); + } +}; diff --git a/tests/unit/test_contracts/capi/crypto.c b/tests/unit/test_contracts/capi/crypto.c index cbe7784c9b..f09f920f17 100644 --- a/tests/unit/test_contracts/capi/crypto.c +++ b/tests/unit/test_contracts/capi/crypto.c @@ -10,6 +10,7 @@ void test_crypto( void ) { sha1( NULL, 0, NULL ); sha512( NULL, 0, NULL ); ripemd160( NULL, 0, NULL ); + verify_rsa_sha256_sig( NULL, 0, NULL, 0, NULL, 0, NULL, 0); recover_key( NULL, NULL, 0, NULL, 0 ); assert_recover_key( NULL, NULL, 0, NULL, 0 ); } diff --git a/tests/unit/test_contracts/capi/privileged.c b/tests/unit/test_contracts/capi/privileged.c index e4ea864c52..de780e982e 100644 --- a/tests/unit/test_contracts/capi/privileged.c +++ b/tests/unit/test_contracts/capi/privileged.c @@ -1,4 +1,5 @@ #include +#include #include void test_privileged( void ) { @@ -11,4 +12,5 @@ void test_privileged( void ) { set_blockchain_parameters_packed(NULL, 0); get_blockchain_parameters_packed(NULL, 0); preactivate_feature(NULL); + set_finalizers(0, NULL, 0); } diff --git a/tests/unit/test_contracts/instant_finality_tests.cpp b/tests/unit/test_contracts/instant_finality_tests.cpp new file mode 100644 index 0000000000..b613cfa92c --- /dev/null +++ b/tests/unit/test_contracts/instant_finality_tests.cpp @@ -0,0 +1,12 @@ +#include +#include + +class [[eosio::contract]] instant_finality_tests : public eosio::contract{ +public: + using contract::contract; + + [[eosio::action]] + void setfinalizer(const eosio::finalizer_policy& finalizer_policy) { + eosio::set_finalizers(finalizer_policy); + } +}; diff --git a/tools/external/CMakeLists.txt b/tools/external/CMakeLists.txt index 57f354da15..eae7583dca 100644 --- a/tools/external/CMakeLists.txt +++ b/tools/external/CMakeLists.txt @@ -1 +1 @@ -add_subdirectory(wabt) \ No newline at end of file +add_subdirectory(wabt) diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index e94e8d57e2..fa6772c93c 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -80,9 +80,9 @@ static cl::opt fno_lto_opt( "fno-lto", cl::desc("Disable LTO"), cl::cat(LD_CAT)); -static cl::opt fno_cfl_aa_opt( - "fno-cfl-aa", - cl::desc("Disable CFL Alias Analysis"), +static cl::opt fcfl_aa_opt( + "fcfl-aa", + cl::desc("Enable CFL Alias Analysis"), cl::cat(LD_CAT)); static cl::opt fno_stack_first_opt( "fno-stack-first", @@ -508,6 +508,7 @@ static void GetLdDefaults(std::vector& ldopts) { else ldopts.insert(ldopts.end(), { "-e", "apply" }); ldopts.insert(ldopts.end(), { "--only-export", "apply:function" }); + ldopts.insert(ldopts.end(), { "--only-export", "*:memory" }); } ldopts.emplace_back("-lc++"); ldopts.emplace_back("-lc"); @@ -616,7 +617,7 @@ static Options CreateOptions(bool add_defaults=true) { else pp_dir = eosio::cdt::whereami::where(); - if (!fno_cfl_aa_opt) { + if (fcfl_aa_opt) { copts.emplace_back("-mllvm"); copts.emplace_back("-use-cfl-aa-in-codegen=both"); agopts.emplace_back("-mllvm"); diff --git a/tools/include/eosio/gen.hpp b/tools/include/eosio/gen.hpp index 3637e74fea..6a6a7bd8c5 100644 --- a/tools/include/eosio/gen.hpp +++ b/tools/include/eosio/gen.hpp @@ -895,7 +895,8 @@ struct generation_utils { "db_idx_long_double_remove", "send_deferred", "send_inline", - "send_context_free_inline" + "send_context_free_inline", + "set_finalizers" }; return write_host_funcs.count(func_decl->getNameInfo().getAsString()) >= 1;