From 653096c87da091bf0055c32d16eafcee596754ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex?= Date: Tue, 5 Aug 2025 13:23:58 +0000 Subject: [PATCH] ci: Witness Generator building (#80) * Implement github workflow for natively building the witness generator in linux, windows and macos. * Add release publishing. --- .github/resources/Makefile.macos | 17 + .github/resources/Makefile.windows | 17 + .github/resources/gmp_patch.macos.hpp | 150 ++++++++ .github/workflows/build-witness-generator.yml | 328 ++++++++++++++++++ 4 files changed, 512 insertions(+) create mode 100644 .github/resources/Makefile.macos create mode 100644 .github/resources/Makefile.windows create mode 100644 .github/resources/gmp_patch.macos.hpp create mode 100644 .github/workflows/build-witness-generator.yml diff --git a/.github/resources/Makefile.macos b/.github/resources/Makefile.macos new file mode 100644 index 0000000..0ee9c92 --- /dev/null +++ b/.github/resources/Makefile.macos @@ -0,0 +1,17 @@ +CC = g++ +CFLAGS = -std=c++11 -O3 -I. -I/opt/homebrew/include -include gmp_patch.macos.hpp +LDFLAGS = -L/opt/homebrew/lib -lgmp + +DEPS_HPP = circom.hpp calcwit.hpp fr.hpp pol.cpp +DEPS_O = main.o calcwit.o fr.o pol.o + +all: pol + +%.o: %.cpp $(DEPS_HPP) + $(CC) -Wno-address-of-packed-member -c $< $(CFLAGS) -o $@ + +pol: $(DEPS_O) + $(CC) -o pol $(DEPS_O) $(LDFLAGS) + +clean: + rm -f *.o pol diff --git a/.github/resources/Makefile.windows b/.github/resources/Makefile.windows new file mode 100644 index 0000000..0aceb95 --- /dev/null +++ b/.github/resources/Makefile.windows @@ -0,0 +1,17 @@ +CC = g++ +CFLAGS = -std=c++11 -O3 -I. -I/include -Duint="unsigned int" +LDFLAGS = -L/lib -lgmp -lmman + +DEPS_HPP = circom.hpp calcwit.hpp fr.hpp pol.cpp +DEPS_O = main.o calcwit.o fr.o pol.o + +all: pol.exe + +%.o: %.cpp $(DEPS_HPP) + $(CC) -Wno-address-of-packed-member -c $< $(CFLAGS) -o $@ + +pol.exe: $(DEPS_O) + $(CC) -o pol.exe $(DEPS_O) $(LDFLAGS) + +clean: + rm -f *.o pol.exe diff --git a/.github/resources/gmp_patch.macos.hpp b/.github/resources/gmp_patch.macos.hpp new file mode 100644 index 0000000..ff06356 --- /dev/null +++ b/.github/resources/gmp_patch.macos.hpp @@ -0,0 +1,150 @@ +#ifndef GMP_PATCH_CAST_HPP +#define GMP_PATCH_CAST_HPP + +#include +#include + +// Workaround for a known macOS issue where certain GMP functions fail to compile +// due to strict type checking, despite uint64_t and mp_limb_t being the same size. +// These wrappers explicitly cast uint64_t parameters to mp_limb_t to resolve the mismatch. + +// Arithmetic Wrappers +inline mp_limb_t gmp_add_n_cast(uint64_t* rp, const uint64_t* up, const uint64_t* vp, mp_size_t n) { + return mpn_add_n(reinterpret_cast(rp), + reinterpret_cast(up), + reinterpret_cast(vp), + n); +} + +inline mp_limb_t gmp_sub_n_cast(uint64_t* rp, const uint64_t* up, const uint64_t* vp, mp_size_t n) { + return mpn_sub_n(reinterpret_cast(rp), + reinterpret_cast(up), + reinterpret_cast(vp), + n); +} + +inline mp_limb_t gmp_add_1_cast(uint64_t* rp, const uint64_t* up, mp_size_t n, mp_limb_t b) { + return mpn_add_1(reinterpret_cast(rp), + reinterpret_cast(up), + n, b); +} + +inline mp_limb_t gmp_sub_1_cast(uint64_t* rp, const uint64_t* up, mp_size_t n, mp_limb_t b) { + return mpn_sub_1(reinterpret_cast(rp), + reinterpret_cast(up), + n, b); +} + +inline int gmp_cmp_cast(const uint64_t* up, const uint64_t* vp, mp_size_t n) { + return mpn_cmp(reinterpret_cast(up), + reinterpret_cast(vp), + n); +} + +inline void gmp_copyi_cast(uint64_t* dst, const uint64_t* src, mp_size_t n) { + mpn_copyi(reinterpret_cast(dst), + reinterpret_cast(src), + n); +} + +inline mp_limb_t gmp_mul_1_cast(uint64_t* rp, const uint64_t* up, mp_size_t n, mp_limb_t b) { + return mpn_mul_1(reinterpret_cast(rp), + reinterpret_cast(up), + n, b); +} + +inline mp_limb_t gmp_addmul_1_cast(uint64_t* rp, const uint64_t* up, mp_size_t n, mp_limb_t b) { + return mpn_addmul_1(reinterpret_cast(rp), + reinterpret_cast(up), + n, b); +} + +inline mp_limb_t gmp_add_cast(uint64_t* rp, const uint64_t* up, mp_size_t un, const uint64_t* vp, mp_size_t vn) { + return mpn_add(reinterpret_cast(rp), + reinterpret_cast(up), un, + reinterpret_cast(vp), vn); +} + +// Logic/Bitwise Wrappers +inline int gmp_zero_p_cast(const uint64_t* up, mp_size_t n) { + return mpn_zero_p(reinterpret_cast(up), n); +} + +inline void gmp_and_n_cast(uint64_t* rp, const uint64_t* up, const uint64_t* vp, mp_size_t n) { + mpn_and_n(reinterpret_cast(rp), + reinterpret_cast(up), + reinterpret_cast(vp), + n); +} + +inline void gmp_com_cast(uint64_t* rp, const uint64_t* up, mp_size_t n) { + mpn_com(reinterpret_cast(rp), + reinterpret_cast(up), + n); +} + +inline void gmp_ior_n_cast(uint64_t* rp, const uint64_t* up, const uint64_t* vp, mp_size_t n) { + mpn_ior_n(reinterpret_cast(rp), + reinterpret_cast(up), + reinterpret_cast(vp), + n); +} + +inline void gmp_xor_n_cast(uint64_t* rp, const uint64_t* up, const uint64_t* vp, mp_size_t n) { + mpn_xor_n(reinterpret_cast(rp), + reinterpret_cast(up), + reinterpret_cast(vp), + n); +} + +// Shift Wrappers + +inline mp_limb_t gmp_lshift_cast(uint64_t* rp, const uint64_t* up, mp_size_t n, unsigned int cnt) { + return mpn_lshift(reinterpret_cast(rp), + reinterpret_cast(up), + n, cnt); +} + +inline mp_limb_t gmp_rshift_cast(uint64_t* rp, const uint64_t* up, mp_size_t n, unsigned int cnt) { + return mpn_rshift(reinterpret_cast(rp), + reinterpret_cast(up), + n, cnt); +} + +// Undefine existing GMP macros +#undef mpn_add_n +#undef mpn_sub_n +#undef mpn_add_1 +#undef mpn_sub_1 +#undef mpn_cmp +#undef mpn_copyi +#undef mpn_mul_1 +#undef mpn_addmul_1 +#undef mpn_add +#undef mpn_zero_p +#undef mpn_and_n +#undef mpn_com +#undef mpn_ior_n +#undef mpn_xor_n +#undef mpn_lshift +#undef mpn_rshift + +// Redefine GMP macros to wrappers +#define mpn_add_n gmp_add_n_cast +#define mpn_sub_n gmp_sub_n_cast +#define mpn_add_1 gmp_add_1_cast +#define mpn_sub_1 gmp_sub_1_cast +#define mpn_cmp gmp_cmp_cast +#define mpn_copyi gmp_copyi_cast +#define mpn_mul_1 gmp_mul_1_cast +#define mpn_addmul_1 gmp_addmul_1_cast +#define mpn_add gmp_add_cast +#define mpn_zero_p gmp_zero_p_cast +#define mpn_and_n gmp_and_n_cast +#define mpn_com gmp_com_cast +#define mpn_ior_n gmp_ior_n_cast +#define mpn_xor_n gmp_xor_n_cast +#define mpn_lshift gmp_lshift_cast +#define mpn_rshift gmp_rshift_cast + +#endif // GMP_PATCH_CAST_HPP diff --git a/.github/workflows/build-witness-generator.yml b/.github/workflows/build-witness-generator.yml new file mode 100644 index 0000000..8b85655 --- /dev/null +++ b/.github/workflows/build-witness-generator.yml @@ -0,0 +1,328 @@ +name: Build Witness Generator + +on: + push: + branches: + - main + tags: + - "v*.*.*" + workflow_dispatch: + inputs: + version: + description: "Version to release. Must follow the format of 'vX.Y.Z'." + required: true + pull_request: # For testing purposes + +jobs: + setup: + name: Define variables and configure environment + runs-on: ubuntu-latest + outputs: + version: ${{ steps.define-version.outputs.version }} + steps: + - name: Define version + id: define-version + env: + # Use the tag name if it is available, otherwise use the input version. + # If neither is available, default to the commit hash. + VERSION: ${{ github.event.release.tag_name || inputs.version }} + run: | + if [ -z "$VERSION" ]; then + echo "No version tag found. Defaulting to commit hash." + VERSION=$GITHUB_SHA + elif [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "VERSION must follow the format of 'vX.Y.Z'. Value: '$VERSION'." + exit 1 + fi + + # Export the version to be used in the following jobs. + echo "version=$VERSION" >> $GITHUB_OUTPUT + + build-linux-native: + name: Build Linux Binary (Native) + runs-on: ubuntu-latest + needs: + - setup + env: + VERSION: ${{ needs.setup.outputs.version }} + OS: linux + ARCH: x86_64 + steps: + - name: Install Rust Toolchain + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: stable + cache: false + + - name: Install Circom + run: | + git clone https://github.com/iden3/circom.git + cd circom + RUSTFLAGS="-A dead_code" cargo build --release + RUSTFLAGS="-A dead_code" cargo install --path circom + circom --version + + - name: Checkout + uses: actions/checkout@v4 + with: + path: repo + + - name: Initialise Submodules + working-directory: repo + run: git submodule update --init --recursive + + - name: Generate C++ Circuit + working-directory: repo/circom_circuits/Mantle + run: circom --c --r1cs --no_asm --O2 pol.circom + + - name: Dependencies - Setup + run: | + sudo apt update + + - name: Dependencies - Install [nlohmann/json] + run: sudo apt install nlohmann-json3-dev + + - name: Compile Circuit + working-directory: repo/circom_circuits/Mantle/pol_cpp + run: make pol + + - name: Bundle + working-directory: repo/circom_circuits/Mantle/pol_cpp + run: tar -czf pol-linux-${{ env.ARCH }}.tar.gz pol pol.dat + + - name: Upload Binary + uses: actions/upload-artifact@v4 + with: + name: pol-${{ env.OS }}-${{ env.ARCH }}.tar.gz + path: repo/circom_circuits/Mantle/pol_cpp/pol-${{ env.OS }}-${{ env.ARCH }}.tar.gz + + build-windows-native: + name: Build Windows Binary (Native) + runs-on: windows-latest + needs: + - setup + env: + VERSION: ${{ needs.setup.outputs.version }} + OS: windows + ARCH: x86_64 + steps: + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + update: true + install: >- + base-devel + mingw-w64-x86_64-toolchain + make + git + + - name: Install Rust Toolchain + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: stable + cache: false + + - name: Install Circom + run: | + git clone https://github.com/iden3/circom.git + cd circom + $env:RUSTFLAGS="-A dead_code"; cargo build --release + $env:RUSTFLAGS="-A dead_code"; cargo install --path circom + circom --version + + - name: Checkout + uses: actions/checkout@v4 + with: + path: repo + + - name: Initialise Submodules + working-directory: repo + run: git submodule update --init --recursive + + - name: Generate C++ Circuit + working-directory: repo/circom_circuits/Mantle + run: circom --c --r1cs --no_asm --O2 pol.circom + + - name: Dependencies - Setup + shell: msys2 {0} + run: mkdir /include + + - name: Dependencies - Install [mman-win32] + shell: msys2 {0} + run: | + git clone https://github.com/alitrack/mman-win32.git + cd mman-win32 + pwd + ./configure --prefix= # Path: / + make + make install + + - name: Dependencies - Install [nlohmann/json] + shell: msys2 {0} + run: | + mkdir -p /include/nlohmann/ + wget -O /include/nlohmann/json.hpp https://github.com/nlohmann/json/releases/download/v3.12.0/json.hpp + + - name: Replace pol Makefile # TODO: Make a fork generate the appropriate Windows Makefile + working-directory: repo + shell: msys2 {0} + run: cp .github/resources/Makefile.${{ env.OS }} circom_circuits/Mantle/pol_cpp/Makefile + + - name: Compile Circuit + shell: msys2 {0} + working-directory: repo/circom_circuits/Mantle/pol_cpp + run: make pol.exe + + - name: Bundle + shell: msys2 {0} + working-directory: repo/circom_circuits/Mantle/pol_cpp + run: | + MINGW_BASE_DIR="/${MSYSTEM,,}" # converts to lowercase, e.g., MINGW64 -> mingw64 + MINGW_DLL_DIR="$MINGW_BASE_DIR/bin" + cp "$MINGW_DLL_DIR"/{libgcc_s_seh-1.dll,libgmp-10.dll,libwinpthread-1.dll,libstdc++-6.dll} . + mv pol.dat pol.exe.dat + tar -czf pol-${{ env.OS }}-${{ env.ARCH }}.tar.gz pol.exe pol.exe.dat *.dll + + - name: Upload Binary + uses: actions/upload-artifact@v4 + with: + name: pol-${{ env.OS }}-${{ env.ARCH }}.tar.gz + path: repo/circom_circuits/Mantle/pol_cpp/pol-${{ env.OS }}-${{ env.ARCH }}.tar.gz + + build-macos-native: + name: Build MacOS Binary (Native) + runs-on: macos-latest + needs: + - setup + env: + VERSION: ${{ needs.setup.outputs.version }} + ARCH: arm64 + OS: macos + steps: + - name: Install Rust Toolchain + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: stable + cache: false + + - name: Install Circom + run: | + git clone https://github.com/iden3/circom.git + cd circom + RUSTFLAGS="-A dead_code" cargo build --release + RUSTFLAGS="-A dead_code" cargo install --path circom + circom --version + + - name: Checkout + uses: actions/checkout@v4 + with: + path: repo + + - name: Initialise Submodules + working-directory: repo + run: git submodule update --init --recursive + + - name: Generate C++ Circuit + working-directory: repo/circom_circuits/Mantle + run: circom --c --r1cs --no_asm --O2 pol.circom + + - name: Dependencies - Setup + run: mkdir include + + - name: Dependencies - Install [nlohmann/json] + run: brew install nlohmann-json + + - name: Replace pol Makefile # TODO: Make a fork generate the appropriate MacOS Makefile + working-directory: repo + run: cp .github/resources/Makefile.${{ env.OS }} circom_circuits/Mantle/pol_cpp/Makefile + + - name: Patch MacOS GMP + working-directory: repo + run: cp .github/resources/gmp_patch.${{ env.OS }}.hpp circom_circuits/Mantle/pol_cpp/gmp_patch.${{ env.OS }}.hpp + + - name: Compile Circuit + working-directory: repo/circom_circuits/Mantle/pol_cpp + run: make pol + + - name: Bundle + working-directory: repo/circom_circuits/Mantle/pol_cpp + run: tar -czf pol-${{ env.OS }}-${{ env.ARCH }}.tar.gz pol pol.dat + + - name: Upload Binary + uses: actions/upload-artifact@v4 + with: + name: pol-${{ env.OS }}-${{ env.ARCH }}.tar.gz + path: repo/circom_circuits/Mantle/pol_cpp/pol-${{ env.OS }}-${{ env.ARCH }}.tar.gz + + publish-release: + name: Create Release + runs-on: ubuntu-latest + needs: + - setup + - build-linux-native + - build-windows-native + - build-macos-native + env: + VERSION: ${{ needs.setup.outputs.version }} + outputs: + upload_url: ${{ steps.create_release.outputs.upload_url }} + steps: + - name: Create Release + uses: actions/create-release@v1 + id: create_release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ env.VERSION }} + release_name: PoL Witness Generator ${{ env.VERSION }} + body: | + This is a release of PoL Witness Generator ${{ env.VERSION }}. + ## Changelog + - feature(X): new feature + - fix(Y): bug description + - feature: performance improvement on Z + ## Checklist + Before publishing please ensure: + - [ ] Description is complete + - [ ] Changelog is correct + - [ ] Assets for all platforms exist + - [ ] Pre-release is checked if necessary + - [ ] Remove this checklist before publishing the release. + draft: true + prerelease: true + + upload-artifacts: + name: Upload Artifacts to Release + runs-on: ubuntu-latest + needs: + - setup + - publish-release + strategy: + fail-fast: false + matrix: + platform: + - os: linux + arch: x86_64 + - os: macos + arch: arm64 + - os: windows + arch: x86_64 + env: + VERSION: ${{ needs.setup.outputs.version }} + UPLOAD_URL: ${{ needs.publish-release.outputs.upload_url }} + ARTIFACT_NAME: pol-${{ matrix.platform.os }}-${{ matrix.platform.arch }}.tar.gz + steps: + - name: Download Artifacts + uses: actions/download-artifact@v4 + with: + name: ${{ env.ARTIFACT_NAME }} + + - name: Upload Artifacts to Release + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ env.UPLOAD_URL }} + asset_path: ${{ env.ARTIFACT_NAME }} + asset_name: ${{ env.ARTIFACT_NAME }} + asset_content_type: application/octet-stream