From 8cd3be1cce2029939f50ffaaf383decf0b048b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pavl=C3=ADn?= Date: Thu, 15 Jan 2026 14:59:12 +0100 Subject: [PATCH] feat(build): add scripts and Dockerfile to enable easy build on RPi --- .dockerignore | 37 ++ .github/resources/prover/Makefile | 11 + scripts/Dockerfile | 81 ++++ scripts/README.md | 103 +++++ scripts/build-local.sh | 707 ++++++++++++++++++++++++++++++ scripts/docker-build.sh | 126 ++++++ 6 files changed, 1065 insertions(+) create mode 100644 .dockerignore create mode 100644 scripts/Dockerfile create mode 100644 scripts/README.md create mode 100755 scripts/build-local.sh create mode 100755 scripts/docker-build.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a8cc78e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,37 @@ +# Docker build context ignore file +# Exclude files that don't need to be in the Docker build context + +# Build artifacts +nomos-circuits-*/ +prover-*/ +verifier-*/ +witness-generators/ +proving-keys/ +*.tar.gz + +# Powers of Tau file (large, will be downloaded inside if needed) +*.ptau + +# Circom build (will be done inside container) +circom/ + +# Generated circuit files +*_cpp/ +*.r1cs +*.zkey +*_verification_key.json + +# Git +.git/ +.github/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# Cache +.docker-cache/ +__pycache__/ +*.pyc \ No newline at end of file diff --git a/.github/resources/prover/Makefile b/.github/resources/prover/Makefile index 25f9bb7..2372413 100644 --- a/.github/resources/prover/Makefile +++ b/.github/resources/prover/Makefile @@ -43,6 +43,17 @@ host_arm64: cmake .. -DTARGET_PLATFORM=aarch64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../package_arm64 && \ make -j$(nproc) -vvv && make install +host_linux_arm64_static: + rm -rf build_prover && mkdir build_prover && cd build_prover && \ + cmake .. \ + -DTARGET_PLATFORM=aarch64 \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=../package \ + -DCMAKE_EXE_LINKER_FLAGS="-static -static-libstdc++ -static-libgcc -no-pie" \ + -DOpenMP_gomp_LIBRARY=$(LIBGOMP_A) \ + -DCMAKE_PREFIX_PATH=depends/gmp/package && \ + make -j$(nproc) -vvv && make install + android: rm -rf build_prover_android && mkdir build_prover_android && cd build_prover_android && \ cmake .. -DTARGET_PLATFORM=ANDROID -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../package_android -DBUILD_TESTS=OFF -DUSE_OPENMP=OFF && \ diff --git a/scripts/Dockerfile b/scripts/Dockerfile new file mode 100644 index 0000000..fb61cb4 --- /dev/null +++ b/scripts/Dockerfile @@ -0,0 +1,81 @@ +# Dockerfile for building Logos Blockchain Circuits +# This provides an isolated build environment to avoid polluting the host system +# +# Usage: +# docker build -t logos-circuits-builder . +# docker run --rm -v $(pwd):/workspace logos-circuits-builder [OPTIONS] +# +# Or use the helper script: +# ./docker-build.sh [OPTIONS] + +FROM ubuntu:22.04 + +# Avoid interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + libgmp-dev \ + libsodium-dev \ + nasm \ + curl \ + m4 \ + nlohmann-json3-dev \ + git \ + xxd \ + ca-certificates \ + gnupg \ + && rm -rf /var/lib/apt/lists/* + +# Install Node.js 20.x +RUN mkdir -p /etc/apt/keyrings \ + && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ + && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \ + && apt-get update \ + && apt-get install -y nodejs \ + && rm -rf /var/lib/apt/lists/* + +# Install snarkjs globally +RUN npm install -g snarkjs@latest + +# Install Rust +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" + +# Clone and build Circom +RUN git clone https://github.com/iden3/circom.git /opt/circom \ + && cd /opt/circom \ + && RUSTFLAGS="-A dead_code" cargo build --release \ + && RUSTFLAGS="-A dead_code" cargo install --path circom + +# Verify installations +RUN circom --version && node --version && npm --version + +# Set up working directory +WORKDIR /workspace + +# Create entrypoint script +RUN echo '#!/bin/bash\n\ +set -e\n\ +cd /workspace\n\ +\n\ +# Mark all directories as safe for git (needed for mounted volumes with different ownership)\n\ +# This is safe in a container context where we control the environment\n\ +git config --global --add safe.directory "*"\n\ +\n\ +# Initialize git submodules if needed (including nested submodules like rapidsnark/depends/*)\n\ +if [ -f .gitmodules ]; then\n\ + git submodule update --init --recursive\n\ +fi\n\ +\n\ +# Run the build script with provided arguments\n\ +# Skip deps, circom, and snarkjs as they are already installed in the container\n\ +exec ./scripts/build-local.sh --skip-deps --skip-circom --skip-snarkjs "$@"\n\ +' > /entrypoint.sh && chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] + +# Default: run full build (pass --help to see options) +CMD [] \ No newline at end of file diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..fb8c03c --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,103 @@ +# Scripts Directory + +This directory contains build scripts for compiling the Logos Blockchain Circuits. + +## Files + +### [`build-local.sh`](build-local.sh) + +The main local build script that replicates the GitHub Actions workflow for local execution on Linux. It handles the complete build pipeline including: + +- Installing system dependencies (build-essential, cmake, libgmp-dev, etc.) +- Installing Rust and Circom compiler +- Installing Node.js and snarkjs +- Downloading Powers of Tau file (~3GB) +- Generating proving keys for all circuits (pol, poq, zksign, poc) +- Compiling witness generators +- Building prover and verifier from rapidsnark +- Creating the final release bundle + +**Usage:** +```bash +./build-local.sh [OPTIONS] +``` + +**Options:** +| Option | Description | +|--------|-------------| +| `--version VERSION` | Set the version (default: v0.0.0-local) | +| `--skip-deps` | Skip installing system dependencies | +| `--skip-circom` | Skip Circom installation | +| `--skip-snarkjs` | Skip snarkjs installation | +| `--skip-ptau` | Skip Powers of Tau download | +| `--skip-proving-keys` | Skip proving key generation | +| `--skip-prover` | Skip prover/verifier compilation | +| `--skip-witness` | Skip witness generator compilation | +| `--circuit CIRCUIT` | Build only specified circuit (pol, poq, zksign, poc) | +| `--clean` | Clean all build artifacts before building | +| `--help` | Show help message | + +### [`docker-build.sh`](docker-build.sh) + +A wrapper script that runs the build inside a Docker container to avoid polluting your host system with dependencies. + +**Usage:** +```bash +./docker-build.sh [OPTIONS] +``` + +All options are passed directly to `build-local.sh` inside the container. + +**Examples:** +```bash +./docker-build.sh # Full build +./docker-build.sh --help # Show build-local.sh help +./docker-build.sh --circuit pol # Build only PoL circuit +./docker-build.sh --clean # Clean and rebuild +./docker-build.sh --skip-ptau # Skip Powers of Tau download +``` + +**Environment Variables:** +| Variable | Description | +|----------|-------------| +| `DOCKER_BUILD=0` | Skip rebuilding the Docker image | +| `DOCKER_NOCACHE=1` | Force rebuild Docker image without cache | +| `SKIP_INSTALL=true` | Install artifacts to `~/.nomos-circuits` after build | + +### [`Dockerfile`](Dockerfile) + +Defines the Docker build environment based on Ubuntu 22.04 with all required dependencies pre-installed: + +- Build tools (gcc, cmake, make, nasm) +- Libraries (libgmp, libsodium, nlohmann-json) +- Node.js 20.x and snarkjs +- Rust and Circom compiler + +The container automatically initializes git submodules and runs the build with `--skip-deps --skip-circom --skip-snarkjs` since these are pre-installed. + +## Output + +The build produces a tarball named `nomos-circuits-{VERSION}-{OS}-{ARCH}.tar.gz` containing: + +``` +nomos-circuits-v0.0.0-local-linux-x86_64/ +├── VERSION +├── prover # Rapidsnark prover binary +├── verifier # Rapidsnark verifier binary +├── pol/ +│ ├── witness_generator +│ ├── witness_generator.dat +│ ├── proving_key.zkey +│ └── verification_key.json +├── poq/ +│ └── ... +├── zksign/ +│ └── ... +└── poc/ + └── ... +``` + +## Requirements + +- **Local build:** Linux x86_64 or aarch64, root access for dependencies +- **Docker build:** Docker installed and running diff --git a/scripts/build-local.sh b/scripts/build-local.sh new file mode 100755 index 0000000..c720ff7 --- /dev/null +++ b/scripts/build-local.sh @@ -0,0 +1,707 @@ +#!/usr/bin/env bash +# +# Local Build Script for Logos Blockchain Circuits +# This script replicates the GitHub Actions workflow for local execution on Linux. +# +# Usage: +# ./build-local.sh [OPTIONS] +# +# Options: +# --version VERSION Set the version (default: v0.0.0-local) +# --skip-deps Skip installing system dependencies +# --skip-circom Skip Circom installation (assumes circom is in PATH) +# --skip-snarkjs Skip snarkjs installation (assumes snarkjs is in PATH) +# --skip-ptau Skip Powers of Tau download (assumes file exists) +# --skip-proving-keys Skip proving key generation (assumes they exist) +# --skip-prover Skip prover/verifier compilation +# --skip-witness Skip witness generator compilation +# --circuit CIRCUIT Build only specified circuit (pol, poq, zksign, poc) +# --clean Clean all build artifacts before building +# --help Show this help message +# +# Requirements: +# - Linux x86_64 +# - Root access (for installing dependencies) or pre-installed dependencies +# - Internet connection (for downloading dependencies) +# + +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Logging functions +log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } +log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +log_error() { echo -e "${RED}[ERROR]${NC} $1"; } + +# Default configuration +VERSION="v0.0.0-local" +OS="linux" +# Auto-detect architecture +MACHINE_ARCH="$(uname -m)" +case "$MACHINE_ARCH" in + x86_64|amd64) + ARCH="x86_64" + ;; + aarch64|arm64) + ARCH="aarch64" + ;; + *) + ARCH="$MACHINE_ARCH" + ;; +esac +PTAU_URL="https://storage.googleapis.com/zkevm/ptau/powersOfTau28_hez_final_17.ptau" +PTAU_FILE="powersOfTau28_hez_final_17.ptau" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Flags +SKIP_DEPS=false +SKIP_CIRCOM=false +SKIP_SNARKJS=false +SKIP_PTAU=false +SKIP_PROVING_KEYS=false +SKIP_PROVER=false +SKIP_WITNESS=false +CLEAN=false +SINGLE_CIRCUIT="" + +# Circuit definitions +declare -A CIRCUITS=( + ["pol"]="mantle/pol.circom:pol:PoL" + ["poq"]="blend/poq.circom:poq:PoQ" + ["zksign"]="mantle/signature.circom:signature:ZKSign" + ["poc"]="mantle/poc.circom:poc:PoC" +) + +# Parse command line arguments +parse_args() { + while [[ $# -gt 0 ]]; do + case $1 in + --version) + VERSION="$2" + shift 2 + ;; + --skip-deps) + SKIP_DEPS=true + shift + ;; + --skip-circom) + SKIP_CIRCOM=true + shift + ;; + --skip-snarkjs) + SKIP_SNARKJS=true + shift + ;; + --skip-ptau) + SKIP_PTAU=true + shift + ;; + --skip-proving-keys) + SKIP_PROVING_KEYS=true + shift + ;; + --skip-prover) + SKIP_PROVER=true + shift + ;; + --skip-witness) + SKIP_WITNESS=true + shift + ;; + --circuit) + SINGLE_CIRCUIT="$2" + shift 2 + ;; + --clean) + CLEAN=true + shift + ;; + --help) + head -n 25 "$0" | tail -n +2 | sed 's/^# //' | sed 's/^#//' + exit 0 + ;; + *) + log_error "Unknown option: $1" + exit 1 + ;; + esac + done +} + +# Clean build artifacts +clean_artifacts() { + log_info "Cleaning build artifacts..." + + # Clean circom build directories + rm -rf circom/ 2>/dev/null || true + + # Clean rapidsnark build + if [[ -d "rapidsnark" ]]; then + cd rapidsnark + make clean 2>/dev/null || true + cd .. + fi + + # Clean circuit build directories + for circuit_key in "${!CIRCUITS[@]}"; do + IFS=':' read -r circuit_path circuit_name display_name <<< "${CIRCUITS[$circuit_key]}" + circuit_dir=$(dirname "$circuit_path") + circuit_filestem=$(basename "$circuit_path" .circom) + + rm -rf "${circuit_dir}/${circuit_filestem}_cpp" 2>/dev/null || true + rm -f "${circuit_dir}/${circuit_filestem}.r1cs" 2>/dev/null || true + rm -f "${circuit_dir}/${circuit_key}.zkey" 2>/dev/null || true + rm -f "${circuit_dir}/${circuit_key}-0.zkey" 2>/dev/null || true + rm -f "${circuit_dir}/${circuit_key}_verification_key.json" 2>/dev/null || true + done + + # Clean bundle directories + rm -rf nomos-circuits-* 2>/dev/null || true + rm -rf prover-* 2>/dev/null || true + rm -rf verifier-* 2>/dev/null || true + rm -rf witness-generators/ 2>/dev/null || true + rm -rf proving-keys/ 2>/dev/null || true + + log_success "Cleaned build artifacts" +} + +# Check system requirements +check_requirements() { + log_info "Checking system requirements..." + + # Check OS + if [[ "$(uname -s)" != "Linux" ]]; then + log_error "This script is designed for Linux. Detected: $(uname -s)" + exit 1 + fi + + # Check architecture + if [[ "$ARCH" != "x86_64" && "$ARCH" != "aarch64" ]]; then + log_warn "This script supports x86_64 and aarch64. Detected: $(uname -m)" + else + log_info "Detected architecture: $ARCH" + fi + + log_success "System requirements check passed" +} + +# Install system dependencies +install_dependencies() { + if [[ "$SKIP_DEPS" == true ]]; then + log_info "Skipping system dependency installation..." + return + fi + + log_info "Installing system dependencies..." + + # Detect package manager + if command -v apt-get &> /dev/null; then + sudo apt-get update -y + sudo apt-get install -y \ + build-essential \ + cmake \ + libgmp-dev \ + libsodium-dev \ + nasm \ + curl \ + m4 \ + nlohmann-json3-dev \ + git + elif command -v dnf &> /dev/null; then + sudo dnf install -y \ + gcc \ + gcc-c++ \ + make \ + cmake \ + gmp-devel \ + libsodium-devel \ + nasm \ + curl \ + m4 \ + json-devel \ + git + elif command -v pacman &> /dev/null; then + sudo pacman -S --noconfirm \ + base-devel \ + cmake \ + gmp \ + libsodium \ + nasm \ + curl \ + m4 \ + nlohmann-json \ + git + else + log_error "Unsupported package manager. Please install dependencies manually:" + log_error " build-essential, cmake, libgmp-dev, libsodium-dev, nasm, curl, m4, nlohmann-json3-dev, git" + exit 1 + fi + + log_success "System dependencies installed" +} + +# Install Rust and Circom +install_circom() { + if [[ "$SKIP_CIRCOM" == true ]]; then + log_info "Skipping Circom installation..." + if ! command -v circom &> /dev/null; then + log_error "circom not found in PATH. Please install it or remove --skip-circom" + exit 1 + fi + return + fi + + log_info "Installing Circom..." + + # Check if Rust is installed + if ! command -v cargo &> /dev/null; then + log_info "Installing Rust..." + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + source "$HOME/.cargo/env" + fi + + # Clone and build Circom + if [[ ! -d "circom" ]]; then + git clone https://github.com/iden3/circom.git + fi + + cd circom + RUSTFLAGS="-A dead_code" cargo build --release + RUSTFLAGS="-A dead_code" cargo install --path circom + cd .. + + # Verify installation + circom --version + + log_success "Circom installed successfully" +} + +# Install Node.js and snarkjs +install_snarkjs() { + if [[ "$SKIP_SNARKJS" == true ]]; then + log_info "Skipping snarkjs installation..." + if ! command -v snarkjs &> /dev/null; then + log_error "snarkjs not found in PATH. Please install it or remove --skip-snarkjs" + exit 1 + fi + return + fi + + log_info "Installing snarkjs..." + + # Check if Node.js is installed + if ! command -v node &> /dev/null; then + log_info "Installing Node.js..." + + # Use NodeSource to install Node.js 20 + if command -v apt-get &> /dev/null; then + curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - + sudo apt-get install -y nodejs + elif command -v dnf &> /dev/null; then + curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash - + sudo dnf install -y nodejs + else + log_error "Please install Node.js 20 manually" + exit 1 + fi + fi + + # Install snarkjs globally + sudo npm install -g snarkjs@latest + + # Verify installation + snarkjs --version || true + + log_success "snarkjs installed successfully" +} + +# Initialize git submodules +init_submodules() { + log_info "Initializing git submodules..." + git submodule update --init --recursive + log_success "Git submodules initialized" +} + +# Download Powers of Tau file +download_ptau() { + if [[ "$SKIP_PTAU" == true ]]; then + log_info "Skipping Powers of Tau download..." + if [[ ! -f "$PTAU_FILE" ]]; then + log_error "Powers of Tau file not found: $PTAU_FILE" + exit 1 + fi + return + fi + + if [[ -f "$PTAU_FILE" ]]; then + log_info "Powers of Tau file already exists, skipping download..." + return + fi + + log_info "Downloading Powers of Tau file (this may take a while, ~3GB)..." + curl -L -o "$PTAU_FILE" "$PTAU_URL" + log_success "Powers of Tau file downloaded" +} + +# Generate proving key for a circuit +generate_proving_key() { + local circuit_key="$1" + + if [[ ! -v CIRCUITS[$circuit_key] ]]; then + log_error "Unknown circuit: $circuit_key" + exit 1 + fi + + IFS=':' read -r circuit_path circuit_name display_name <<< "${CIRCUITS[$circuit_key]}" + local circuit_dir=$(dirname "$circuit_path") + local circuit_file=$(basename "$circuit_path") + local circuit_filestem=$(basename "$circuit_path" .circom) + + log_info "Generating proving key for $display_name..." + + cd "$circuit_dir" + + # Generate R1CS + log_info " Generating R1CS constraints..." + circom --r1cs --O2 "$circuit_file" + + # Determine the R1CS file name (some circuits have different names) + local r1cs_file="${circuit_filestem}.r1cs" + + # Setup + log_info " Running Groth16 setup..." + snarkjs groth16 setup "$r1cs_file" "../$PTAU_FILE" "${circuit_key}-0.zkey" + + # Contribute to ceremony + log_info " Contributing to ceremony..." + head -c 32 /dev/urandom | xxd -p -c 256 | snarkjs zkey contribute "${circuit_key}-0.zkey" "${circuit_key}.zkey" --name="LOCAL_BUILD" -v + + # Export verification key + log_info " Exporting verification key..." + snarkjs zkey export verificationkey "${circuit_key}.zkey" "${circuit_key}_verification_key.json" + + # Cleanup intermediate file + rm -f "${circuit_key}-0.zkey" + + cd "$SCRIPT_DIR" + + log_success "Proving key generated for $display_name" +} + +# Generate all proving keys +generate_all_proving_keys() { + if [[ "$SKIP_PROVING_KEYS" == true ]]; then + log_info "Skipping proving key generation..." + return + fi + + log_info "Generating proving keys for all circuits..." + + local circuits_to_build + if [[ -n "$SINGLE_CIRCUIT" ]]; then + circuits_to_build=("$SINGLE_CIRCUIT") + else + circuits_to_build=("${!CIRCUITS[@]}") + fi + + for circuit_key in "${circuits_to_build[@]}"; do + generate_proving_key "$circuit_key" + done + + log_success "All proving keys generated" +} + +# Compile witness generator for a circuit +compile_witness_generator() { + local circuit_key="$1" + + if [[ ! -v CIRCUITS[$circuit_key] ]]; then + log_error "Unknown circuit: $circuit_key" + exit 1 + fi + + IFS=':' read -r circuit_path circuit_name display_name <<< "${CIRCUITS[$circuit_key]}" + local circuit_dir=$(dirname "$circuit_path") + local circuit_file=$(basename "$circuit_path") + local circuit_filestem=$(basename "$circuit_path" .circom) + local circuit_cpp_dir="${circuit_dir}/${circuit_filestem}_cpp" + + log_info "Compiling witness generator for $display_name..." + + cd "$circuit_dir" + + # Generate C++ code for witness computation + log_info " Generating C++ code..." + circom --c --r1cs --no_asm --O2 "$circuit_file" + + # Replace Makefile with our custom one + log_info " Copying custom Makefile..." + cp "$SCRIPT_DIR/.github/resources/witness-generator/Makefile" "${circuit_filestem}_cpp/Makefile" + + # Compile the witness generator + log_info " Compiling..." + cd "${circuit_filestem}_cpp" + make PROJECT="$circuit_filestem" linux + + cd "$SCRIPT_DIR" + + log_success "Witness generator compiled for $display_name" +} + +# Compile all witness generators +compile_all_witness_generators() { + if [[ "$SKIP_WITNESS" == true ]]; then + log_info "Skipping witness generator compilation..." + return + fi + + log_info "Compiling witness generators for all circuits..." + + local circuits_to_build + if [[ -n "$SINGLE_CIRCUIT" ]]; then + circuits_to_build=("$SINGLE_CIRCUIT") + else + circuits_to_build=("${!CIRCUITS[@]}") + fi + + for circuit_key in "${circuits_to_build[@]}"; do + compile_witness_generator "$circuit_key" + done + + log_success "All witness generators compiled" +} + +# Download GMP archive if needed +download_gmp() { + local gmp_dir="rapidsnark/depends" + local gmp_file="gmp-6.2.1.tar.xz" + + if [[ -f "$gmp_dir/$gmp_file" ]]; then + log_info "GMP archive already exists, skipping download..." + return + fi + + log_info "Downloading GMP archive..." + mkdir -p "$gmp_dir" + curl -L -o "$gmp_dir/$gmp_file" "https://ftpmirror.gnu.org/gmp/gmp-6.2.1.tar.xz" + log_success "GMP archive downloaded" +} + +# Compile prover and verifier +compile_prover_verifier() { + if [[ "$SKIP_PROVER" == true ]]; then + log_info "Skipping prover/verifier compilation..." + return + fi + + log_info "Compiling prover and verifier..." + + # Replace Makefile with our custom one + log_info " Replacing Makefile..." + cp ".github/resources/prover/Makefile" "rapidsnark/Makefile" + + # Download GMP if needed + download_gmp + + cd rapidsnark + + # Build GMP (ignore exit code if already built) + log_info " Building GMP..." + ./build_gmp.sh host || true + + # Verify GMP is available + if [[ ! -d "depends/gmp/package" ]]; then + log_error "GMP package not found after build_gmp.sh" + exit 1 + fi + + # For ARM64, CMake expects package_aarch64 but build_gmp.sh host creates package + # Create symlink to fix the path mismatch + if [[ "$ARCH" == "aarch64" ]]; then + if [[ -d "depends/gmp/package" && ! -e "depends/gmp/package_aarch64" ]]; then + log_info " Creating symlink for ARM64 GMP package..." + ln -s package depends/gmp/package_aarch64 + fi + fi + + # Build prover and verifier based on architecture + log_info " Building prover and verifier (static) for $ARCH..." + if [[ "$ARCH" == "aarch64" ]]; then + make host_linux_arm64_static + else + make host_linux_x86_64_static + fi + + cd "$SCRIPT_DIR" + + log_success "Prover and verifier compiled" +} + +# Create the unified release bundle +create_bundle() { + local bundle_name="nomos-circuits-${VERSION}-${OS}-${ARCH}" + + log_info "Creating unified release bundle: $bundle_name" + + # Create bundle directory structure + mkdir -p "${bundle_name}"/{pol,poq,zksign,poc} + + # Create VERSION file + echo "$VERSION" > "${bundle_name}/VERSION" + + # Copy prover and verifier + if [[ ! "$SKIP_PROVER" == true ]]; then + log_info " Copying prover and verifier..." + cp "rapidsnark/package/bin/prover" "${bundle_name}/prover" + cp "rapidsnark/package/bin/verifier" "${bundle_name}/verifier" + chmod +x "${bundle_name}/prover" + chmod +x "${bundle_name}/verifier" + fi + + # Copy witness generators and proving keys for each circuit + local circuits_to_bundle + if [[ -n "$SINGLE_CIRCUIT" ]]; then + circuits_to_bundle=("$SINGLE_CIRCUIT") + else + circuits_to_bundle=("${!CIRCUITS[@]}") + fi + + for circuit_key in "${circuits_to_bundle[@]}"; do + IFS=':' read -r circuit_path circuit_name display_name <<< "${CIRCUITS[$circuit_key]}" + local circuit_dir=$(dirname "$circuit_path") + local circuit_filestem=$(basename "$circuit_path" .circom) + local circuit_cpp_dir="${circuit_dir}/${circuit_filestem}_cpp" + + log_info " Bundling $display_name..." + + # Copy witness generator + if [[ ! "$SKIP_WITNESS" == true ]]; then + if [[ -f "${circuit_cpp_dir}/${circuit_filestem}" ]]; then + cp "${circuit_cpp_dir}/${circuit_filestem}" "${bundle_name}/${circuit_key}/witness_generator" + chmod +x "${bundle_name}/${circuit_key}/witness_generator" + fi + if [[ -f "${circuit_cpp_dir}/${circuit_filestem}.dat" ]]; then + cp "${circuit_cpp_dir}/${circuit_filestem}.dat" "${bundle_name}/${circuit_key}/witness_generator.dat" + fi + fi + + # Copy proving key and verification key + if [[ ! "$SKIP_PROVING_KEYS" == true ]]; then + if [[ -f "${circuit_dir}/${circuit_key}.zkey" ]]; then + cp "${circuit_dir}/${circuit_key}.zkey" "${bundle_name}/${circuit_key}/proving_key.zkey" + fi + if [[ -f "${circuit_dir}/${circuit_key}_verification_key.json" ]]; then + cp "${circuit_dir}/${circuit_key}_verification_key.json" "${bundle_name}/${circuit_key}/verification_key.json" + fi + fi + done + + # Create tarball + log_info " Creating tarball..." + tar -czf "${bundle_name}.tar.gz" "${bundle_name}" + + log_success "Bundle created: ${bundle_name}.tar.gz" + + # Print bundle contents + log_info "Bundle contents:" + tar -tzf "${bundle_name}.tar.gz" | head -50 +} + +# Print build summary +print_summary() { + echo "" + log_info "==========================================" + log_info "Build Summary" + log_info "==========================================" + log_info "Version: $VERSION" + log_info "OS: $OS" + log_info "Architecture: $ARCH" + echo "" + + if [[ -n "$SINGLE_CIRCUIT" ]]; then + log_info "Built circuit: $SINGLE_CIRCUIT" + else + log_info "Built circuits: pol, poq, zksign, poc" + fi + echo "" + + log_info "Skip flags:" + log_info " - Dependencies: $SKIP_DEPS" + log_info " - Circom: $SKIP_CIRCOM" + log_info " - snarkjs: $SKIP_SNARKJS" + log_info " - Powers of Tau: $SKIP_PTAU" + log_info " - Proving Keys: $SKIP_PROVING_KEYS" + log_info " - Prover/Verifier: $SKIP_PROVER" + log_info " - Witness Generators: $SKIP_WITNESS" + echo "" + + local bundle_name="nomos-circuits-${VERSION}-${OS}-${ARCH}" + if [[ -f "${bundle_name}.tar.gz" ]]; then + local size=$(du -h "${bundle_name}.tar.gz" | cut -f1) + log_success "Output bundle: ${bundle_name}.tar.gz ($size)" + fi + log_info "==========================================" +} + +# Main function +main() { + parse_args "$@" + + echo "" + log_info "==========================================" + log_info "Logos Blockchain Circuits - Local Build" + log_info "==========================================" + log_info "Version: $VERSION" + log_info "Starting build process..." + echo "" + + # Clean if requested + if [[ "$CLEAN" == true ]]; then + clean_artifacts + fi + + # Check requirements + check_requirements + + # Install dependencies + install_dependencies + + # Initialize submodules + init_submodules + + # Install Circom + install_circom + + # Install snarkjs + install_snarkjs + + # Download Powers of Tau + download_ptau + + # Generate proving keys + generate_all_proving_keys + + # Compile prover and verifier + compile_prover_verifier + + # Compile witness generators + compile_all_witness_generators + + # Create bundle + create_bundle + + # Print summary + print_summary + + log_success "Build completed successfully!" +} + +# Run main function +main "$@" \ No newline at end of file diff --git a/scripts/docker-build.sh b/scripts/docker-build.sh new file mode 100755 index 0000000..b908fe9 --- /dev/null +++ b/scripts/docker-build.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +# +# Docker Build Script for Logos Blockchain Circuits +# This script builds and runs the circuit compilation in a Docker container +# to avoid polluting your host system. +# +# Usage: +# ./docker-build.sh [OPTIONS] +# +# Options: +# All options are passed directly to build-local.sh inside the container. +# See ./build-local.sh --help for available options. +# +# Examples: +# ./docker-build.sh # Full build +# ./docker-build.sh --help # Show build-local.sh help +# ./docker-build.sh --circuit pol # Build only PoL circuit +# ./docker-build.sh --clean # Clean and rebuild +# ./docker-build.sh --skip-ptau # Skip Powers of Tau download (if already exists) +# +# Advanced Options: +# DOCKER_BUILD=0 ./docker-build.sh # Skip rebuilding the Docker image +# DOCKER_NOCACHE=1 ./docker-build.sh # Force rebuild Docker image without cache +# + +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } +log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +log_error() { echo -e "${RED}[ERROR]${NC} $1"; } + +# Configuration +IMAGE_NAME="logos-circuits-builder" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"/.. +DOCKER_BUILD="${DOCKER_BUILD:-1}" +DOCKER_NOCACHE="${DOCKER_NOCACHE:-0}" +SKIP_INSTALL=${SKIP_INSTALL:-false} + +cd "$SCRIPT_DIR" + + +# Check if Docker is installed +if ! command -v docker &> /dev/null; then + log_error "Docker is not installed. Please install Docker first." + exit 1 +fi + +# Check if Docker daemon is running +if ! docker info &> /dev/null; then + log_error "Docker daemon is not running. Please start Docker first." + exit 1 +fi + +# Build the Docker image if needed +if [[ "$DOCKER_BUILD" == "1" ]]; then + log_info "Building Docker image: $IMAGE_NAME" + + BUILD_ARGS="" + if [[ "$DOCKER_NOCACHE" == "1" ]]; then + BUILD_ARGS="--no-cache" + fi + + ls + docker build $BUILD_ARGS -t "$IMAGE_NAME" -f ./scripts/Dockerfile . + log_success "Docker image built successfully" +else + log_info "Skipping Docker image build (DOCKER_BUILD=0)" +fi + +# Run the build in Docker +log_info "Running build in Docker container..." +log_info "Arguments: $*" + +# Use interactive mode if terminal is available, for better output +DOCKER_FLAGS="-it" +if [[ ! -t 0 ]]; then + DOCKER_FLAGS="" +fi + +# Run the container with the workspace mounted +# --rm: Remove container after exit +# -v: Mount current directory to /workspace +# -v for ptau: Persist the Powers of Tau file to avoid re-downloading +docker run --rm $DOCKER_FLAGS \ + -v "$SCRIPT_DIR:/workspace" \ + -v "$SCRIPT_DIR/.docker-cache:/root/.cache" \ + -e "TERM=${TERM:-xterm}" \ + "$IMAGE_NAME" "$@" + +log_success "Docker build completed!" + +if [[ $SKIP_INSTALL == false ]]; then + log_info "Remember to install the built artifacts if needed." + exit 0 +fi + +DEFAULT_INSTALL_DIR="$HOME/.nomos-circuits" + +log_info "Installing built artifacts to $DEFAULT_INSTALL_DIR" +mkdir -p "$DEFAULT_INSTALL_DIR" + +# Default configuration +VERSION="v0.0.0-local" +OS="linux" +# Auto-detect architecture +MACHINE_ARCH="$(uname -m)" +case "$MACHINE_ARCH" in + x86_64|amd64) + ARCH="x86_64" + ;; + aarch64|arm64) + ARCH="aarch64" + ;; + *) + ARCH="$MACHINE_ARCH" + ;; +esac +cp -r ./nomos-circuits-$VERSION-$OS-$ARCH/* "$DEFAULT_INSTALL_DIR/" \ No newline at end of file