From 37570240e61db5a4f812313eee009213fbc73ec8 Mon Sep 17 00:00:00 2001 From: Alejandro Cabeza Romero Date: Thu, 2 Oct 2025 17:55:20 +0200 Subject: [PATCH 1/2] Migrate circuits from nomos-pocs. --- .github/actions/compile-and-bundle/action.yml | 128 +++++ .github/resources/prover/Makefile | 118 ++++ .github/resources/prover/windows.build_gmp.sh | 423 ++++++++++++++ .../resources/prover/windows.mman_patch.hpp | 7 + .../prover/windows.src-CMakeLists.txt | 181 ++++++ .github/resources/prover/windows.uio.h | 19 + .github/resources/witness-generator/Makefile | 43 ++ .../witness-generator/macos.gmp_patch.hpp | 150 +++++ .github/workflows/build-circuits.yml | 537 ++++++++++++++++++ .gitmodules | 6 + blend/generate_inputs_for_poq.py | 331 +++++++++++ blend/poq.circom | 137 +++++ hash_bn/merkle.circom | 55 ++ hash_bn/poseidon2_hash.circom | 19 + hash_bn/poseidon2_perm.circom | 217 +++++++ hash_bn/poseidon2_sponge.circom | 123 ++++ ledger/notes.circom | 30 + mantle/generate_inputs_for_pol.py | 308 ++++++++++ mantle/generate_inputs_for_proof_of_claim.py | 238 ++++++++ mantle/generate_inputs_for_signature.py | 232 ++++++++ mantle/poc.circom | 74 +++ mantle/pol.circom | 5 + mantle/pol_lib.circom | 248 ++++++++ mantle/signature.circom | 24 + misc/comparator.circom | 80 +++ misc/constants.circom | 67 +++ 26 files changed, 3800 insertions(+) create mode 100644 .github/actions/compile-and-bundle/action.yml create mode 100644 .github/resources/prover/Makefile create mode 100755 .github/resources/prover/windows.build_gmp.sh create mode 100644 .github/resources/prover/windows.mman_patch.hpp create mode 100644 .github/resources/prover/windows.src-CMakeLists.txt create mode 100644 .github/resources/prover/windows.uio.h create mode 100644 .github/resources/witness-generator/Makefile create mode 100644 .github/resources/witness-generator/macos.gmp_patch.hpp create mode 100644 .github/workflows/build-circuits.yml create mode 100644 .gitmodules create mode 100644 blend/generate_inputs_for_poq.py create mode 100644 blend/poq.circom create mode 100644 hash_bn/merkle.circom create mode 100644 hash_bn/poseidon2_hash.circom create mode 100644 hash_bn/poseidon2_perm.circom create mode 100644 hash_bn/poseidon2_sponge.circom create mode 100644 ledger/notes.circom create mode 100755 mantle/generate_inputs_for_pol.py create mode 100755 mantle/generate_inputs_for_proof_of_claim.py create mode 100755 mantle/generate_inputs_for_signature.py create mode 100644 mantle/poc.circom create mode 100644 mantle/pol.circom create mode 100644 mantle/pol_lib.circom create mode 100644 mantle/signature.circom create mode 100644 misc/comparator.circom create mode 100644 misc/constants.circom diff --git a/.github/actions/compile-and-bundle/action.yml b/.github/actions/compile-and-bundle/action.yml new file mode 100644 index 0000000..ae7c624 --- /dev/null +++ b/.github/actions/compile-and-bundle/action.yml @@ -0,0 +1,128 @@ +name: "Compile and Bundle Circuit" +description: "Compiles and bundles the witness generator of a Circom Circuit" +branding: + icon: "package" + color: "blue" + +inputs: + circuit-name-display: + description: "The name of the Circom circuit to compile." + required: true + circuit-name-binary: + description: "The final name of the compiled binary. The name should be extensionless." + required: true + circuit-path: + description: "The path to the Circom circuit file relative to the repository root." + required: true + resources-path: + description: "The path to the CI resources directory relative to the repository root." + required: false + default: ".github/resources" + version: + description: "The version of the bundle. E.g.: v1.0.0." + required: true + os: + description: "The target operating system for the bundle (linux, windows, macos)." + required: true + arch: + description: "The target architecture for the bundle (x86_64, aarch64)." + required: true + +runs: + using: "composite" + steps: + - name: Parse Circuit Path + id: parse-circuit-path + shell: bash + env: + CIRCUIT_PATH: ${{ inputs.circuit-path }} + BUNDLE_TRIPLET: ${{ inputs.version }}-${{ inputs.os }}-${{ inputs.arch }} + CIRCUIT_NAME_BINARY: ${{ inputs.circuit-name-binary }} + RESOURCES_PATH: ${{ inputs.resources-path }} + OS: ${{ inputs.os }} + run: | + CIRCUIT_DIRECTORY="$(dirname ${CIRCUIT_PATH})" + CIRCUIT_FILENAME="$(basename ${CIRCUIT_PATH})" + CIRCUIT_FILESTEM="${CIRCUIT_FILENAME%.circom}" + CIRCUIT_CPP_DIRNAME="${CIRCUIT_FILESTEM}_cpp" + + platform_binary_name="${CIRCUIT_NAME_BINARY}" + if [ "${OS}" = "windows" ]; then + platform_binary_name="${platform_binary_name}.exe" + fi + + { + echo "CIRCUIT_DIRECTORY=${CIRCUIT_DIRECTORY}" + echo "CIRCUIT_FILENAME=${CIRCUIT_FILENAME}" + echo "CIRCUIT_FILESTEM=${CIRCUIT_FILESTEM}" + echo "CIRCUIT_CPP_DIRNAME=${CIRCUIT_CPP_DIRNAME}" + echo "CIRCUIT_CPP_PATH=${CIRCUIT_DIRECTORY}/${CIRCUIT_CPP_DIRNAME}" + echo "WITNESS_GENERATOR_RESOURCES_PATH=${RESOURCES_PATH}/witness-generator" + echo "BUNDLE_TRIPLET=${BUNDLE_TRIPLET}" + echo "PLATFORM_BINARY_NAME=${platform_binary_name}" + } >> "${GITHUB_OUTPUT}" + + - name: Generate ${{ inputs.circuit-name-display }} + shell: bash + working-directory: ${{ steps.parse-circuit-path.outputs.CIRCUIT_DIRECTORY }} + env: + CIRCUIT_FILENAME: ${{ steps.parse-circuit-path.outputs.CIRCUIT_FILENAME }} + run: circom --c --r1cs --no_asm --O2 "${CIRCUIT_FILENAME}" + + # TODO: Instead of replace, make a fork that generates the appropriate Makefile + - name: Replace ${{ inputs.circuit-name-display }}'s Makefile + shell: bash + env: + WITNESS_GENERATOR_RESOURCES_PATH: ${{ steps.parse-circuit-path.outputs.WITNESS_GENERATOR_RESOURCES_PATH }} + CIRCUIT_CPP_PATH: ${{ steps.parse-circuit-path.outputs.CIRCUIT_CPP_PATH }} + run: cp "${WITNESS_GENERATOR_RESOURCES_PATH}/Makefile" "${CIRCUIT_CPP_PATH}/Makefile" + + # TODO: Instead of insertion, make a fork that includes the appropriate patch (or the actual fix) + - name: Patch MacOS GMP + shell: bash + if: ${{ inputs.os == 'macos' }} + env: + WITNESS_GENERATOR_RESOURCES_PATH: ${{ steps.parse-circuit-path.outputs.WITNESS_GENERATOR_RESOURCES_PATH }} + CIRCUIT_CPP_PATH: ${{ steps.parse-circuit-path.outputs.CIRCUIT_CPP_PATH }} + OS: ${{ inputs.os }} + run: cp "${WITNESS_GENERATOR_RESOURCES_PATH}/${{ env.OS }}.gmp_patch.hpp" "${CIRCUIT_CPP_PATH}/gmp_patch.hpp" + + - name: Compile ${{ inputs.circuit-name-display }} + if: ${{ inputs.os != 'windows' }} + shell: bash + working-directory: ${{ steps.parse-circuit-path.outputs.CIRCUIT_CPP_PATH }} + env: + CIRCUIT_FILESTEM: ${{ steps.parse-circuit-path.outputs.CIRCUIT_FILESTEM }} + OS: ${{ inputs.os }} + run: make PROJECT="${CIRCUIT_FILESTEM}" "${OS}" + + - name: Compile ${{ inputs.circuit-name-display }} + if: ${{ inputs.os == 'windows' }} + shell: msys2 {0} + working-directory: ${{ steps.parse-circuit-path.outputs.CIRCUIT_CPP_PATH }} + env: + CIRCUIT_FILESTEM: ${{ steps.parse-circuit-path.outputs.CIRCUIT_FILESTEM }} + OS: ${{ inputs.os }} + run: make PROJECT="${CIRCUIT_FILESTEM}" "${OS}" + + - name: Bundle ${{ inputs.circuit-name-display }} + shell: bash + env: + CIRCUIT_NAME: ${{ steps.parse-circuit-path.outputs.CIRCUIT_FILESTEM }} + PLATFORM_BINARY_NAME: ${{ steps.parse-circuit-path.outputs.PLATFORM_BINARY_NAME }} + BUNDLE_NAME: ${{ inputs.circuit-name-binary }}-${{ steps.parse-circuit-path.outputs.BUNDLE_TRIPLET }} + WITNESS_GENERATOR_DIR: ${{ steps.parse-circuit-path.outputs.CIRCUIT_CPP_PATH }} + run: | + BUNDLE_DIR="${BUNDLE_NAME}/witness-generator" + mkdir -p "$BUNDLE_DIR" + + mv "${WITNESS_GENERATOR_DIR}/${CIRCUIT_NAME}" "$BUNDLE_DIR/${PLATFORM_BINARY_NAME}" + mv "${WITNESS_GENERATOR_DIR}/${CIRCUIT_NAME}.dat" "$BUNDLE_DIR/${PLATFORM_BINARY_NAME}.dat" + + tar -czf "${BUNDLE_NAME}.tar.gz" "${BUNDLE_NAME}" + + - name: Upload ${{ inputs.circuit-name-display }} + uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 + with: + name: ${{ inputs.circuit-name-binary }}-${{ steps.parse-circuit-path.outputs.BUNDLE_TRIPLET }}.tar.gz + path: ${{ inputs.circuit-name-binary }}-${{ steps.parse-circuit-path.outputs.BUNDLE_TRIPLET }}.tar.gz diff --git a/.github/resources/prover/Makefile b/.github/resources/prover/Makefile new file mode 100644 index 0000000..25f9bb7 --- /dev/null +++ b/.github/resources/prover/Makefile @@ -0,0 +1,118 @@ +### + +EXTRA_CMAKE_FLAGS ?= +LIBGOMP_A := $(shell $(CXX) --print-file-name=libgomp.a) + +#Build targets +# Add EXTRA_CMAKE_FLAGS +host: + rm -rf build_prover && mkdir build_prover && cd build_prover && \ + cmake .. \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=../package \ + $(EXTRA_CMAKE_FLAGS) && \ + make -j$(nproc) -vvv && make install + +host_linux_x86_64_static: + rm -rf build_prover && mkdir build_prover && cd build_prover && \ + cmake .. \ + -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 + +host_windows_x86_64_static: + rm -rf build_prover && mkdir build_prover && cd build_prover && \ + cmake .. \ + -DUSE_ASM=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=../package \ + -DCMAKE_EXE_LINKER_FLAGS="-static -static-libstdc++ -static-libgcc -L/lib -lmman" \ + -DCMAKE_CXX_FLAGS="-I/include -include mman_patch.hpp -include cstdint -Duint=unsigned\ int -Du_int32_t=uint32_t -Du_int64_t=uint64_t" && \ + make -j$(nproc) -vvv && make install + +host_noasm: + rm -rf build_prover_noasm && mkdir build_prover_noasm && cd build_prover_noasm && \ + cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../package_noasm -DUSE_ASM=NO && \ + make -j$(nproc) -vvv && make install + +host_arm64: + rm -rf build_prover_arm64 && mkdir build_prover_arm64 && cd build_prover_arm64 && \ + cmake .. -DTARGET_PLATFORM=aarch64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../package_arm64 && \ + 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 && \ + make -j$(nproc) -vvv && make install + +android_openmp: + rm -rf build_prover_android_openmp && mkdir build_prover_android_openmp && cd build_prover_android_openmp && \ + cmake .. -DTARGET_PLATFORM=ANDROID -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../package_android_openmp -DBUILD_TESTS=OFF -DUSE_OPENMP=ON && \ + make -j$(nproc) -vvv && make install + +android_x86_64: + rm -rf build_prover_android_x86_64 && mkdir build_prover_android_x86_64 && cd build_prover_android_x86_64 && \ + cmake .. -DTARGET_PLATFORM=ANDROID_x86_64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../package_android_x86_64 -DBUILD_TESTS=OFF -DUSE_OPENMP=OFF && \ + make -j$(nproc) -vvv && make install + +android_openmp_x86_64: + rm -rf build_prover_android_openmp_x86_64 && mkdir build_prover_android_openmp_x86_64 && cd build_prover_android_openmp_x86_64 && \ + cmake .. -DTARGET_PLATFORM=ANDROID_x86_64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../package_android_openmp_x86_64 -DBUILD_TESTS=OFF -DUSE_OPENMP=ON && \ + make -j$(nproc) -vvv && make install + +ios: + @if [ ! -d "./depends/gmp/package_ios_arm64" ]; then echo "Looks like gmp lib is not built. Run './build_gmp.sh ios' first." && exit 1; fi + rm -rf build_prover_ios && mkdir build_prover_ios && cd build_prover_ios && \ + cmake .. -GXcode -DTARGET_PLATFORM=IOS -DCMAKE_INSTALL_PREFIX=../package_ios && \ + xcodebuild -destination 'generic/platform=iOS' -scheme rapidsnarkStatic -project rapidsnark.xcodeproj -configuration Release && \ + xcodebuild -destination 'generic/platform=iOS' -scheme rapidsnark -project rapidsnark.xcodeproj -configuration Release CODE_SIGNING_ALLOWED=NO && \ + cp ../depends/gmp/package_ios_arm64/lib/libgmp.a src/Release-iphoneos && \ + echo "" && echo "iOS Simulator artifacts built in build_prover_ios/src/Release-iphoneos" && echo "" + +ios_simulator: + @if [ ! -d "./depends/gmp/package_iphone_simulator" ]; then echo "Looks like gmp lib is not built. Run './build_gmp.sh ios_simulator' first." && exit 1; fi + rm -rf build_prover_ios_simulator && mkdir build_prover_ios_simulator && cd build_prover_ios_simulator && \ + cmake .. -GXcode -DTARGET_PLATFORM=IOS_SIMULATOR -DCMAKE_INSTALL_PREFIX=../package_ios_simulator -DUSE_ASM=NO && \ + xcodebuild -destination 'generic/platform=iOS Simulator' -scheme rapidsnarkStatic -project rapidsnark.xcodeproj && \ + xcodebuild -destination 'generic/platform=iOS Simulator' -scheme rapidsnark -project rapidsnark.xcodeproj CODE_SIGNING_ALLOWED=NO ARCHS=arm64 && \ + cp ../depends/gmp/package_iphone_simulator/lib/libgmp.a src/Debug-iphonesimulator && \ + echo "" && echo "iOS Simulator artifacts built in build_prover_ios_simulator/src/Debug-iphonesimulator" && echo "" + +macos_arm64: + @if [ ! -d "./depends/gmp/package_macos_arm64" ]; then echo "Looks like gmp lib is not built. Run './build_gmp.sh macos_arm64' first." && exit 1; fi + rm -rf build_prover_macos_arm64 && mkdir build_prover_macos_arm64 && cd build_prover_macos_arm64 && \ + cmake .. -DTARGET_PLATFORM=macos_arm64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../package_macos_arm64 && \ + make -j$(nproc) -vvv && make install + +macos_x86_64: + @if [ ! -d "./depends/gmp/package_macos_x86_64" ]; then echo "Looks like gmp lib is not built. Run './build_gmp.sh macos_x86_64' first." && exit 1; fi + rm -rf build_prover_macos_x86_64 && mkdir build_prover_macos_x86_64 && cd build_prover_macos_x86_64 && \ + cmake .. -DTARGET_PLATFORM=macos_x86_64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../package_macos_x86_64 && \ + make -j$(nproc) -vvv && make install + +clean: + rm -rf build_prover \ + build_prover_macos_arm64 \ + build_prover_macos_x86_64 \ + build_prover_android \ + build_prover_android_x86_64 \ + build_prover_ios \ + build_prover_ios_simulator \ + package \ + package_macos_arm64 \ + package_macos_x86_64 \ + package_android \ + package_android_x86_64 \ + package_ios \ + package_ios_simulator \ + depends/gmp/package \ + depends/gmp/package_macos_arm64 \ + depends/gmp/package_macos_x86_64 \ + depends/gmp/package_android_arm64 \ + depends/gmp/package_android_x86_64 \ + depends/gmp/package_ios_arm64 \ + depends/gmp/package_iphone_simulator + diff --git a/.github/resources/prover/windows.build_gmp.sh b/.github/resources/prover/windows.build_gmp.sh new file mode 100755 index 0000000..245ec0a --- /dev/null +++ b/.github/resources/prover/windows.build_gmp.sh @@ -0,0 +1,423 @@ +#!/usr/bin/env bash + +set -e + +NPROC=8 +fetch_cmd=$( (type wget > /dev/null 2>&1 && echo "wget") || echo "curl -O" ) + +usage() +{ + echo "USAGE: $0 " + echo "where target is one of:" + echo " ios: build for iOS arm64" + echo " ios_simulator: build for iPhone Simulator for arm64/x86_64 (fat binary)" + echo " macos: build for macOS for arm64/x86_64 (fat binary)" + echo " macos_arm64: build for macOS arm64" + echo " macos_x86_64: build for macOS x86_64" + echo " android: build for Android arm64" + echo " android_x86_64: build for Android x86_64" + echo " host: build for this host" + echo " host_noasm: build for this host without asm optimizations (e.g. needed for macOS)" + echo " aarch64: build for Linux aarch64" + + exit 1 +} + +get_gmp() +{ + GMP_NAME=gmp-6.2.1 + GMP_ARCHIVE=${GMP_NAME}.tar.xz + GMP_URL=https://ftp.gnu.org/gnu/gmp/${GMP_ARCHIVE} + + if [ ! -f ${GMP_ARCHIVE} ]; then + + $fetch_cmd ${GMP_URL} + fi + + + if [ ! -d gmp ]; then + + tar -xvf ${GMP_ARCHIVE} + mv ${GMP_NAME} gmp + fi +} + +build_aarch64() +{ + PACKAGE_DIR="$GMP_DIR/package_aarch64" + BUILD_DIR=build_aarch64 + + if [ -d "$PACKAGE_DIR" ]; then + echo "aarch64 package is built already. See $PACKAGE_DIR" + return 1 + fi + + + export TARGET=aarch64-linux-gnu + + echo $TARGET + + rm -rf "$BUILD_DIR" + mkdir "$BUILD_DIR" + cd "$BUILD_DIR" + + ../configure --host $TARGET --prefix="$PACKAGE_DIR" --with-pic --disable-fft && + make -j${NPROC} && + make install + + cd .. +} + +build_host() +{ + PACKAGE_DIR="$GMP_DIR/package" + BUILD_DIR=build + + if [ -d "$PACKAGE_DIR" ]; then + echo "Host package is built already. See $PACKAGE_DIR" + return 1 + fi + + rm -rf "$BUILD_DIR" + mkdir "$BUILD_DIR" + cd "$BUILD_DIR" + + # The following line is a workaround for the Windows build due to an existing incompatibility with current compiler + # when building GMP. + CFLAGS="-O2 -std=gnu17" CXXFLAGS="-O2 -std=gnu++17" \ + ../configure --prefix="$PACKAGE_DIR" --with-pic --disable-fft && + make -j${NPROC} && + make install + + cd .. +} + +build_host_noasm() +{ + PACKAGE_DIR="$GMP_DIR/package" + BUILD_DIR=build + + if [ -d "$PACKAGE_DIR" ]; then + echo "Host package is built already. See $PACKAGE_DIR" + return 1 + fi + + rm -rf "$BUILD_DIR" + mkdir "$BUILD_DIR" + cd "$BUILD_DIR" + + ../configure --prefix="$PACKAGE_DIR" --with-pic --disable-fft --disable-assembly && + make -j${NPROC} && + make install + + cd .. +} + +build_android() +{ + PACKAGE_DIR="$GMP_DIR/package_android_arm64" + BUILD_DIR=build_android_arm64 + + if [ -d "$PACKAGE_DIR" ]; then + echo "Android package is built already. See $PACKAGE_DIR" + return 1 + fi + + if [ -z "$ANDROID_NDK" ]; then + + echo "ERROR: ANDROID_NDK environment variable is not set." + echo " It must be an absolute path to the root directory of Android NDK." + echo " For instance /home/test/Android/Sdk/ndk/23.1.7779620" + return 1 + fi + + if [ "$(uname)" == "Darwin" ]; then + export TOOLCHAIN=$ANDROID_NDK/toolchains/llvm/prebuilt/darwin-x86_64 + else + export TOOLCHAIN=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64 + fi + + export TARGET=aarch64-linux-android + export API=21 + + export AR=$TOOLCHAIN/bin/llvm-ar + export CC=$TOOLCHAIN/bin/$TARGET$API-clang + export AS=$CC + export CXX=$TOOLCHAIN/bin/$TARGET$API-clang++ + export LD=$TOOLCHAIN/bin/ld + export RANLIB=$TOOLCHAIN/bin/llvm-ranlib + export STRIP=$TOOLCHAIN/bin/llvm-strip + + echo "$TOOLCHAIN" + echo "$TARGET" + + rm -rf "$BUILD_DIR" + mkdir "$BUILD_DIR" + cd "$BUILD_DIR" + + ../configure --host $TARGET --prefix="$PACKAGE_DIR" --with-pic --disable-fft && + make -j${NPROC} && + make install + + cd .. +} + +build_android_x86_64() +{ + PACKAGE_DIR="$GMP_DIR/package_android_x86_64" + BUILD_DIR=build_android_x86_64 + + if [ -d "$PACKAGE_DIR" ]; then + echo "Android package is built already. See $PACKAGE_DIR" + return 1 + fi + + if [ -z "$ANDROID_NDK" ]; then + + echo "ERROR: ANDROID_NDK environment variable is not set." + echo " It must be an absolute path to the root directory of Android NDK." + echo " For instance /home/test/Android/Sdk/ndk/23.1.7779620" + return 1 + fi + + if [ "$(uname)" == "Darwin" ]; then + export TOOLCHAIN=$ANDROID_NDK/toolchains/llvm/prebuilt/darwin-x86_64 + else + export TOOLCHAIN=$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64 + fi + + export TARGET=x86_64-linux-android + export API=21 + + export AR=$TOOLCHAIN/bin/llvm-ar + export CC=$TOOLCHAIN/bin/$TARGET$API-clang + export AS=$CC + export CXX=$TOOLCHAIN/bin/$TARGET$API-clang++ + export LD=$TOOLCHAIN/bin/ld + export RANLIB=$TOOLCHAIN/bin/llvm-ranlib + export STRIP=$TOOLCHAIN/bin/llvm-strip + + echo "$TOOLCHAIN" + echo $TARGET + + rm -rf "$BUILD_DIR" + mkdir "$BUILD_DIR" + cd "$BUILD_DIR" + + ../configure --host $TARGET --prefix="$PACKAGE_DIR" --with-pic --disable-fft && + make -j${NPROC} && + make install + + cd .. +} + +build_ios() +{ + PACKAGE_DIR="$GMP_DIR/package_ios_arm64" + BUILD_DIR=build_ios_arm64 + + if [ -d "$PACKAGE_DIR" ]; then + echo "iOS package is built already. See $PACKAGE_DIR" + return 1 + fi + + export SDK="iphoneos" + export TARGET=arm64-apple-darwin + export MIN_IOS_VERSION=8.0 + + export ARCH_FLAGS="-arch arm64 -arch arm64e" + export OPT_FLAGS="-O3 -g3 -fembed-bitcode" + HOST_FLAGS="${ARCH_FLAGS} -miphoneos-version-min=${MIN_IOS_VERSION} -isysroot $(xcrun --sdk ${SDK} --show-sdk-path)" + + CC=$(xcrun --find --sdk "${SDK}" clang) + export CC + CXX=$(xcrun --find --sdk "${SDK}" clang++) + export CXX + CPP=$(xcrun --find --sdk "${SDK}" cpp) + export CPP + export CFLAGS="${HOST_FLAGS} ${OPT_FLAGS}" + export CXXFLAGS="${HOST_FLAGS} ${OPT_FLAGS}" + export LDFLAGS="${HOST_FLAGS}" + + echo $TARGET + + rm -rf "$BUILD_DIR" + mkdir "$BUILD_DIR" + cd "$BUILD_DIR" + + ../configure --host $TARGET --prefix="$PACKAGE_DIR" --with-pic --disable-fft --disable-assembly && + make -j${NPROC} && + make install + + cd .. +} + +build_ios_simulator() +{ + libs=() + for ARCH in "arm64" "x86_64"; do + case "$ARCH" in + "arm64" ) + echo "Building for iPhone Simulator arm64" + ARCH_FLAGS="-arch arm64 -arch arm64e" + ;; + "x86_64" ) + echo "Building for iPhone Simulator x86_64" + ARCH_FLAGS="-arch x86_64" + ;; + * ) + echo "Incorrect iPhone Simulator arch" + exit 1 + esac + + BUILD_DIR="build_iphone_simulator_${ARCH}" + PACKAGE_DIR="$GMP_DIR/package_iphone_simulator_${ARCH}" + libs+=("${PACKAGE_DIR}/lib/libgmp.a") + + if [ -d "$PACKAGE_DIR" ]; then + echo "iPhone Simulator ${ARCH} package is built already. See $PACKAGE_DIR. Skip building this ARCH." + continue + fi + + rm -rf "$BUILD_DIR" + mkdir "$BUILD_DIR" + cd "$BUILD_DIR" + + ../configure --prefix="${PACKAGE_DIR}" \ + CC="$(xcrun --sdk iphonesimulator --find clang)" \ + CFLAGS="-O3 -isysroot $(xcrun --sdk iphonesimulator --show-sdk-path) ${ARCH_FLAGS} -fvisibility=hidden -mios-simulator-version-min=8.0" \ + LDFLAGS="" \ + --host ${ARCH}-apple-darwin --disable-assembly --enable-static --disable-shared --with-pic && + make -j${NPROC} && + make install + + cd .. + done + + mkdir -p "${GMP_DIR}/package_iphone_simulator/lib" + lipo "${libs[@]}" -create -output "${GMP_DIR}/package_iphone_simulator/lib/libgmp.a" + echo "Wrote universal fat library for iPhone Simulator arm64/x86_64 to ${GMP_DIR}/package_iphone_simulator/lib/libgmp.a" +} + +build_macos_arch() +{ + ARCH="$1" + case "$ARCH" in + "arm64" ) + ARCH_FLAGS="-arch arm64 -arch arm64e" + ;; + "x86_64" ) + ARCH_FLAGS="-arch x86_64" + ;; + * ) + echo "Incorrect arch" + exit 1 + esac + + BUILD_DIR="build_macos_${ARCH}" + PACKAGE_DIR="$GMP_DIR/package_macos_${ARCH}" + if [ -d "$PACKAGE_DIR" ]; then + echo "macOS ${ARCH} package is built already. See $PACKAGE_DIR. Skip building this ARCH." + return + fi + rm -rf "$BUILD_DIR" + mkdir "$BUILD_DIR" + cd "$BUILD_DIR" + ../configure --prefix="${PACKAGE_DIR}" \ + CC="$(xcrun --sdk macosx --find clang)" \ + CFLAGS="-O3 -isysroot $(xcrun --sdk macosx --show-sdk-path) ${ARCH_FLAGS} -fvisibility=hidden -mmacos-version-min=14.0" \ + LDFLAGS="" \ + --host "${ARCH}-apple-darwin" --disable-assembly --enable-static --disable-shared --with-pic && + make -j${NPROC} && + make install + cd .. +} + +build_macos_fat() +{ + echo "Building for macOS arm64" + build_macos_arch "arm64" + echo "Building for macOS x86_64" + build_macos_arch "x86_64" + + gmp_lib_arm64="$GMP_DIR/package_macos_arm64/lib/libgmp.a" + gmp_lib_x86_64="$GMP_DIR/package_macos_x86_64/lib/libgmp.a" + gmp_lib_fat="$GMP_DIR/package_macos/lib/libgmp.a" + + mkdir -p "${GMP_DIR}/package_macos/lib" + lipo "${gmp_lib_arm64}" "${gmp_lib_x86_64}" -create -output "${gmp_lib_fat}" + mkdir -p "${GMP_DIR}/package_macos/include" + cp "${GMP_DIR}/package_macos_arm64/include/gmp.h" "${GMP_DIR}/package_macos/include/" + echo "Wrote universal fat library for macOS arm64/x86_64 to ${GMP_DIR}/package_macos/lib/libgmp.a" +} + +if [ $# -ne 1 ]; then + usage +fi + +TARGET_PLATFORM=$(echo "$1" | tr "[:upper:]" "[:lower:]") + +cd depends + +get_gmp + +cd gmp + +GMP_DIR=$PWD + +case "$TARGET_PLATFORM" in + + "ios" ) + echo "Building for ios" + build_ios + ;; + + "ios_simulator" ) + echo "Building for iPhone Simulator" + build_ios_simulator + ;; + + "macos" ) + echo "Building fat library for macOS" + build_macos_fat + ;; + + "macos_arm64" ) + echo "Building library for macOS arm64" + build_macos_arch "arm64" + ;; + + "macos_x86_64" ) + echo "Building library for macOS x86_64" + build_macos_arch "x86_64" + ;; + + "android" ) + echo "Building for android" + build_android + ;; + + "android_x86_64" ) + echo "Building for android x86_64" + build_android_x86_64 + ;; + + "host" ) + echo "Building for this host" + build_host + ;; + + "host_noasm" ) + echo "Building for this host without asm optimizations (e.g. needed for macOS)" + build_host_noasm + ;; + + "aarch64" ) + echo "Building for linux aarch64" + build_aarch64 + ;; + + * ) + usage + +esac diff --git a/.github/resources/prover/windows.mman_patch.hpp b/.github/resources/prover/windows.mman_patch.hpp new file mode 100644 index 0000000..718acb3 --- /dev/null +++ b/.github/resources/prover/windows.mman_patch.hpp @@ -0,0 +1,7 @@ +// Workaround for Windows where some mman functions are not defined + +#ifdef _WIN32 +#include +inline int madvise(void*, size_t, int) { return 0; } +#define MADV_SEQUENTIAL 0 +#endif diff --git a/.github/resources/prover/windows.src-CMakeLists.txt b/.github/resources/prover/windows.src-CMakeLists.txt new file mode 100644 index 0000000..d97580f --- /dev/null +++ b/.github/resources/prover/windows.src-CMakeLists.txt @@ -0,0 +1,181 @@ +# Workaround for CMake on Windows to +# Added explicit linking (e.g., mman), which are otherwise resolved transitively on Linux and macOS. + +find_library(MMAN_LIB mman PATHS /lib NO_DEFAULT_PATH REQUIRED) + +link_libraries(${GMP_LIB}) + +add_definitions(${GMP_DEFINIONS}) + +if(USE_ASM) + if(ARCH MATCHES "arm64") + add_definitions(-DUSE_ASM -DARCH_ARM64) + elseif(ARCH MATCHES "x86_64") + add_definitions(-DUSE_ASM -DARCH_X86_64) + endif() +endif() + +if(DEFINED BITS_PER_CHUNK) + add_definitions(-DMSM_BITS_PER_CHUNK=${BITS_PER_CHUNK}) +endif() + +if(USE_ASM AND ARCH MATCHES "x86_64") + + if (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin" AND NOT TARGET_PLATFORM MATCHES "^android(_x86_64)?") + set(NASM_FLAGS -fmacho64 --prefix _) + else() + set(NASM_FLAGS -felf64 -DPIC) + endif() + + add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/build/fq_asm.o + COMMAND nasm ${NASM_FLAGS} fq.asm -o fq_asm.o + DEPENDS ${CMAKE_SOURCE_DIR}/build/fq.asm + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/build) + + add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/build/fr_asm.o + COMMAND nasm ${NASM_FLAGS} fr.asm -o fr_asm.o + DEPENDS ${CMAKE_SOURCE_DIR}/build/fr.asm + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/build) +endif() + +set(FR_SOURCES + ../build/fr.hpp + ../build/fr.cpp + ) + +if(USE_ASM) + if(ARCH MATCHES "arm64") + set(FR_SOURCES ${FR_SOURCES} ../build/fr_raw_arm64.s ../build/fr_raw_generic.cpp ../build/fr_generic.cpp) + elseif(ARCH MATCHES "x86_64") + set(FR_SOURCES ${FR_SOURCES} ../build/fr_asm.o) + endif() +else() + set(FR_SOURCES ${FR_SOURCES} ../build/fr_generic.cpp ../build/fr_raw_generic.cpp) +endif() + +add_library(fr STATIC ${FR_SOURCES}) +set_target_properties(fr PROPERTIES POSITION_INDEPENDENT_CODE ON) + +link_libraries(fr) + +set(FQ_SOURCES + ../build/fq.hpp + ../build/fq.cpp + ) + +if(USE_ASM) + if(ARCH MATCHES "arm64") + set(FQ_SOURCES ${FQ_SOURCES} ../build/fq_raw_arm64.s ../build/fq_raw_generic.cpp ../build/fq_generic.cpp) + elseif(ARCH MATCHES "x86_64") + set(FQ_SOURCES ${FQ_SOURCES} ../build/fq_asm.o) + endif() +else() + set(FQ_SOURCES ${FQ_SOURCES} ../build/fq_raw_generic.cpp ../build/fq_generic.cpp) +endif() + +add_library(fq STATIC ${FQ_SOURCES}) +set_target_properties(fq PROPERTIES POSITION_INDEPENDENT_CODE ON) + +link_libraries(fq) + + +if(OpenMP_CXX_FOUND) + add_definitions(-DUSE_OPENMP) + add_compile_options(${OpenMP_CXX_FLAGS}) +endif() + +set(LIB_SOURCES + binfile_utils.hpp + binfile_utils.cpp + zkey_utils.hpp + zkey_utils.cpp + wtns_utils.hpp + wtns_utils.cpp + logger.hpp + logger.cpp + fileloader.cpp + fileloader.hpp + prover.cpp + prover.h + verifier.cpp + verifier.h + ../depends/ffiasm/c/misc.cpp + ../depends/ffiasm/c/naf.cpp + ../depends/ffiasm/c/splitparstr.cpp + ../depends/ffiasm/c/alt_bn128.cpp + ) + +if(USE_LOGGER) + set(LIB_SOURCES ${LIB_SOURCES} logger.cpp) + add_definitions(-DUSE_LOGGER) +endif() + +include_directories( + ../src + ../build + ../depends/ffiasm/c + ../depends/json/single_include + /include +) + +add_library(rapidsnarkStatic STATIC ${LIB_SOURCES}) +set_target_properties(rapidsnarkStatic PROPERTIES OUTPUT_NAME rapidsnark) + +add_library(rapidsnarkStaticFrFq STATIC ${LIB_SOURCES} ${FQ_SOURCES} ${FR_SOURCES}) +set_target_properties(rapidsnarkStaticFrFq PROPERTIES POSITION_INDEPENDENT_CODE ON) +set_target_properties(rapidsnarkStaticFrFq PROPERTIES OUTPUT_NAME rapidsnark-fr-fq) + +add_executable(prover main_prover.cpp) +target_link_libraries( + prover rapidsnarkStatic + fr fq ${MMAN_LIB} # Explicit linking +) + +add_executable(verifier main_verifier.cpp) +target_link_libraries( + verifier rapidsnarkStatic + fr fq ${MMAN_LIB} # Explicit linking +) + +add_library(rapidsnark SHARED ${LIB_SOURCES}) +target_link_libraries(rapidsnark ${MMAN_LIB}) # Explicit linking + +if((USE_LOGGER OR NOT USE_OPENMP) AND NOT TARGET_PLATFORM MATCHES "android") + target_link_libraries(prover pthread) + target_link_libraries(verifier pthread) +endif() + +if(USE_SODIUM) + target_link_libraries(prover sodium) +endif() + +option(BUILD_TESTS "Build the tests" ON) + +if(BUILD_TESTS) + enable_testing() + add_executable(test_public_size test_public_size.c) + target_link_libraries( + test_public_size rapidsnarkStaticFrFq pthread + ${MMAN_LIB} # Explicit linking + ) + add_test(NAME test_public_size COMMAND test_public_size circuit_final.zkey 86 + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/testdata) +endif() + +if(OpenMP_CXX_FOUND) + + if(TARGET_PLATFORM MATCHES "android") + target_link_libraries(prover -static-openmp -fopenmp) + target_link_libraries(verifier -static-openmp -fopenmp) + target_link_libraries(rapidsnark -static-openmp -fopenmp) + + elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + target_link_libraries(prover OpenMP::OpenMP_CXX) + target_link_libraries(verifier OpenMP::OpenMP_CXX) + target_link_libraries(test_public_size OpenMP::OpenMP_CXX) + endif() + +endif() + + +add_executable(test_prover test_prover.cpp) diff --git a/.github/resources/prover/windows.uio.h b/.github/resources/prover/windows.uio.h new file mode 100644 index 0000000..8ac0de2 --- /dev/null +++ b/.github/resources/prover/windows.uio.h @@ -0,0 +1,19 @@ +// Workaround for Windows UIO header, as it's not available by default + +#ifndef SYS_UIO_H +#define SYS_UIO_H + +#include +#include + +struct iovec +{ + void *iov_base; + size_t iov_len; +}; + +ssize_t readv(int fildes, const struct iovec *iov, int iovcnt); +ssize_t writev(int fildes, const struct iovec *iov, int iovcnt); + +#endif + diff --git a/.github/resources/witness-generator/Makefile b/.github/resources/witness-generator/Makefile new file mode 100644 index 0000000..57cf692 --- /dev/null +++ b/.github/resources/witness-generator/Makefile @@ -0,0 +1,43 @@ +.PHONY: linux macos windows build clean + +# ---- Arguments ---- +ifndef PROJECT +$(error PROJECT is not set. Usage: make PROJECT=. E.g.: make PROJECT=pol linux) +endif + +# ---- Common ---- +CXX := g++ +CXXFLAGS_COMMON := -std=c++11 -O3 -I. -Wno-address-of-packed-member +SRCS := main.cpp calcwit.cpp fr.cpp $(PROJECT).cpp +OBJS := $(SRCS:.cpp=.o) +DEPS_HPP := circom.hpp calcwit.hpp fr.hpp +BIN := $(PROJECT) + +# ---- Linux ---- +linux: CXXFLAGS=$(CXXFLAGS_COMMON) +linux: LDFLAGS=-static +linux: LDLIBS=-lgmp +linux: $(BIN) + +# ---- macOS ---- +macos: CXXFLAGS=$(CXXFLAGS_COMMON) -I/opt/homebrew/include -include gmp_patch.hpp +macos: LDFLAGS=-Wl,-search_paths_first -Wl,-dead_strip +macos: LDLIBS=/opt/homebrew/lib/libgmp.a +macos: $(BIN) + +# ---- Windows (MinGW) ---- +windows: CXXFLAGS=$(CXXFLAGS_COMMON) -I/include -Duint="unsigned int" +windows: LDFLAGS=-static +windows: LDLIBS=-L/lib -lgmp -lmman +windows: $(BIN) + +# ---- Rules ---- +$(BIN): $(OBJS) + $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +%.o: %.cpp $(DEPS_HPP) + $(CXX) $(CXXFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJS) $(BIN) + diff --git a/.github/resources/witness-generator/macos.gmp_patch.hpp b/.github/resources/witness-generator/macos.gmp_patch.hpp new file mode 100644 index 0000000..53ff683 --- /dev/null +++ b/.github/resources/witness-generator/macos.gmp_patch.hpp @@ -0,0 +1,150 @@ +// 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. + +#ifndef GMP_PATCH_CAST_HPP +#define GMP_PATCH_CAST_HPP + +#include +#include + +// 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-circuits.yml b/.github/workflows/build-circuits.yml new file mode 100644 index 0000000..a58169e --- /dev/null +++ b/.github/workflows/build-circuits.yml @@ -0,0 +1,537 @@ +name: Build Circuits + +on: + push: + tags: + - "circom_circuits-v*.*.*" + workflow_dispatch: + inputs: + tag: + description: "Tag to release. Must follow the format of 'circom_circuits-vX.Y.Z'." + required: true + +jobs: + setup: + name: Configure Environment + runs-on: ubuntu-latest + outputs: + version: ${{ steps.define-version.outputs.version }} + tag: ${{ steps.define-version.outputs.tag }} + 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. + TAG: ${{ (github.ref_type == 'tag' && github.ref_name) || inputs.tag || '' }} + run: | + if [ -z "$TAG" ]; then + echo "Could not determine tag." + exit 1 + elif [[ ! "$TAG" =~ ^circom_circuits-v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "TAG must follow the format of 'circom_circuits-vX.Y.Z'. Value: '$VERSION'." + exit 2 + fi + + # Parse Version: Take only the vX.Y.Z part. + VERSION=$(echo $TAG | cut -d'-' -f2) + + # Export the tag and version. + echo "tag=$TAG" >> $GITHUB_OUTPUT + echo "version=$VERSION" >> $GITHUB_OUTPUT + + build-linux: + name: Build Linux Binaries (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@fb51252c7ba57d633bc668f941da052e410add48 + 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@8edcb1bdb4e267140fa742c62e395cd74f332709 + + - name: Initialise Submodules + run: git submodule update --init --recursive + + - name: Setup Dependencies + working-directory: circom_circuits/rapidsnark + run: sudo apt update -y + + - name: Install Dependencies [Prover] + run: sudo apt install -y build-essential cmake libgmp-dev libsodium-dev nasm curl m4 + + - name: Install Dependencies [Witness Generator] + run: sudo apt install nlohmann-json3-dev + + - name: Replace Prover Makefile # TODO: Make a fork generate the appropriate Linux Makefile + run: cp .github/resources/prover/Makefile circom_circuits/rapidsnark/Makefile + + - name: Compile Prover and Verifier + working-directory: circom_circuits/rapidsnark + run: | + ./build_gmp.sh host + make host_linux_x86_64_static + + - name: Bundle Rapidsnark Prover + env: + BINARY_NAME: prover + BUNDLE_NAME: prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }} + RAPIDSNARK_DIR: circom_circuits/rapidsnark/package + run: | + BUNDLE_DIR="${BUNDLE_NAME}/${BINARY_NAME}" + mkdir -p "$BUNDLE_DIR" + + mv "${RAPIDSNARK_DIR}"/bin/${BINARY_NAME} "$BUNDLE_DIR/" + + tar -czf "${BUNDLE_NAME}.tar.gz" "${BUNDLE_NAME}" + + - name: Bundle Rapidsnark Verifier + env: + BINARY_NAME: verifier + BUNDLE_NAME: verifier-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }} + RAPIDSNARK_DIR: circom_circuits/rapidsnark/package + run: | + BUNDLE_DIR="${BUNDLE_NAME}/${BINARY_NAME}" + mkdir -p "$BUNDLE_DIR" + + mv "${RAPIDSNARK_DIR}"/bin/${BINARY_NAME} "$BUNDLE_DIR/" + + tar -czf "${BUNDLE_NAME}.tar.gz" "${BUNDLE_NAME}" + + - name: Upload Rapidsnark Prover + uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 + with: + name: prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz + path: prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz + + - name: Upload Rapidsnark Verifier + uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 + with: + name: verifier-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz + path: verifier-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz + + - name: Compile and Bundle PoL + uses: ./.github/actions/compile-and-bundle + with: + circuit-name-display: "PoL" + circuit-name-binary: "pol" + circuit-path: "circom_circuits/Mantle/pol.circom" + version: ${{ env.VERSION }} + os: ${{ env.OS }} + arch: ${{ env.ARCH }} + + - name: Compile and Bundle PoQ + uses: ./.github/actions/compile-and-bundle + with: + circuit-name-display: "PoQ" + circuit-name-binary: "poq" + circuit-path: "circom_circuits/Blend/poq.circom" + version: ${{ env.VERSION }} + os: ${{ env.OS }} + arch: ${{ env.ARCH }} + + - name: Compile and Bundle ZKSign + uses: ./.github/actions/compile-and-bundle + with: + circuit-name-display: "ZKSign" + circuit-name-binary: "zksign" + circuit-path: "circom_circuits/Mantle/signature.circom" + version: ${{ env.VERSION }} + os: ${{ env.OS }} + arch: ${{ env.ARCH }} + + - name: Compile and Bundle PoC + uses: ./.github/actions/compile-and-bundle + with: + circuit-name-display: "PoC" + circuit-name-binary: "poc" + circuit-path: "circom_circuits/Mantle/poc.circom" + version: ${{ env.VERSION }} + os: ${{ env.OS }} + arch: ${{ env.ARCH }} + + build-windows: + name: Build Windows Binaries (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.28.0 # FIXME: Ideally use the hash to avoid supply chain attacks. Currently unable to. + with: + update: true + install: >- + base-devel + mingw-w64-x86_64-toolchain + make + git + + - name: Install Rust Toolchain + uses: actions-rust-lang/setup-rust-toolchain@fb51252c7ba57d633bc668f941da052e410add48 + 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@8edcb1bdb4e267140fa742c62e395cd74f332709 + + - name: Initialise Submodules + run: git submodule update --init --recursive + + - name: Install Dependencies [Witness Generator] + shell: msys2 {0} + run: | + # nlohmann/json + mkdir -p /include/nlohmann/ + wget -O /include/nlohmann/json.hpp https://github.com/nlohmann/json/releases/download/v3.12.0/json.hpp + + # mman-win32 + git clone https://github.com/alitrack/mman-win32.git + pushd mman-win32 + ./configure --prefix= # Path: / + make + make install + popd + + - name: Install Dependencies [Prover] + shell: msys2 {0} + run: pacman --noconfirm -Sy --needed cmake nasm mingw-w64-ucrt-x86_64-libsodium + + - name: Replace Prover Makefile # TODO: Make a fork generate the appropriate Windows Makefile + shell: msys2 {0} + run: cp .github/resources/prover/Makefile circom_circuits/rapidsnark/Makefile + + - name: Replace Prover CMakeLists + shell: msys2 {0} + run: cp .github/resources/prover/${{ env.OS }}.src-CMakeLists.txt circom_circuits/rapidsnark/src/CMakeLists.txt + + - name: Patch Windows mman + shell: msys2 {0} + run: cp .github/resources/prover/${{ env.OS }}.mman_patch.hpp /include/mman_patch.hpp + + - name: Add uio.h headers + shell: msys2 {0} + run: cp .github/resources/prover/${{ env.OS }}.uio.h /include/sys/uio.h + + - name: Replace build_gmp + shell: msys2 {0} + run: cp .github/resources/prover/${{ env.OS }}.build_gmp.sh circom_circuits/rapidsnark/build_gmp.sh + + - name: Compile Prover and Verifier + shell: msys2 {0} + working-directory: circom_circuits/rapidsnark + run: | + ./build_gmp.sh host + make host_windows_x86_64_static + + - name: Bundle Rapidsnark Prover + shell: msys2 {0} + env: + BINARY_NAME: prover + BUNDLE_NAME: prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }} + RAPIDSNARK_DIR: circom_circuits/rapidsnark/package + run: | + BUNDLE_DIR="${BUNDLE_NAME}/${BINARY_NAME}" + mkdir -p "$BUNDLE_DIR" + + mv "${RAPIDSNARK_DIR}"/bin/${BINARY_NAME}.exe "$BUNDLE_DIR/" + + tar -czf "${BUNDLE_NAME}.tar.gz" "${BUNDLE_NAME}" + + - name: Bundle Rapidsnark Verifier + shell: msys2 {0} + env: + BINARY_NAME: verifier + BUNDLE_NAME: verifier-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }} + RAPIDSNARK_DIR: circom_circuits/rapidsnark/package + run: | + BUNDLE_DIR="${BUNDLE_NAME}/${BINARY_NAME}" + mkdir -p "$BUNDLE_DIR" + + mv "${RAPIDSNARK_DIR}"/bin/${BINARY_NAME}.exe "$BUNDLE_DIR/" + + tar -czf "${BUNDLE_NAME}.tar.gz" "${BUNDLE_NAME}" + + - name: Upload Rapidsnark Prover + uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 + with: + name: prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz + path: prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz + + - name: Upload Rapidsnark Verifier + uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 + with: + name: verifier-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz + path: verifier-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz + + - name: Compile and Bundle PoL + uses: ./.github/actions/compile-and-bundle + with: + circuit-name-display: "PoL" + circuit-name-binary: "pol" + circuit-path: "circom_circuits/Mantle/pol.circom" + version: ${{ env.VERSION }} + os: ${{ env.OS }} + arch: ${{ env.ARCH }} + + - name: Compile and Bundle PoQ + uses: ./.github/actions/compile-and-bundle + with: + circuit-name-display: "PoQ" + circuit-name-binary: "poq" + circuit-path: "circom_circuits/Blend/poq.circom" + version: ${{ env.VERSION }} + os: ${{ env.OS }} + arch: ${{ env.ARCH }} + + - name: Compile and Bundle ZKSign + uses: ./.github/actions/compile-and-bundle + with: + circuit-name-display: "ZKSign" + circuit-name-binary: "zksign" + circuit-path: "circom_circuits/Mantle/signature.circom" + version: ${{ env.VERSION }} + os: ${{ env.OS }} + arch: ${{ env.ARCH }} + + - name: Compile and Bundle PoC + uses: ./.github/actions/compile-and-bundle + with: + circuit-name-display: "PoC" + circuit-name-binary: "poc" + circuit-path: "circom_circuits/Mantle/poc.circom" + version: ${{ env.VERSION }} + os: ${{ env.OS }} + arch: ${{ env.ARCH }} + + build-macos: + name: Build MacOS Binaries (Native) + runs-on: macos-latest + needs: + - setup + env: + VERSION: ${{ needs.setup.outputs.version }} + ARCH: aarch64 + OS: macos + steps: + - name: Install Rust Toolchain + uses: actions-rust-lang/setup-rust-toolchain@fb51252c7ba57d633bc668f941da052e410add48 + 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@8edcb1bdb4e267140fa742c62e395cd74f332709 + + - name: Initialise Submodules + run: git submodule update --init --recursive + + - name: Setup Dependencies + run: mkdir include + + - name: Install Dependencies [Witness Generator] + run: brew install nlohmann-json + + - name: Install Dependencies [Prover] + run: brew install nasm m4 + + - name: Compile Prover and Verifier + working-directory: circom_circuits/rapidsnark + run: | + ./build_gmp.sh macos_arm64 + make macos_arm64 + + - name: Bundle Rapidsnark Prover + env: + BINARY_NAME: prover + BUNDLE_NAME: prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }} + RAPIDSNARK_DIR: circom_circuits/rapidsnark/package_macos_arm64 + run: | + BUNDLE_DIR="${BUNDLE_NAME}/${BINARY_NAME}" + mkdir -p "$BUNDLE_DIR" + + mv "${RAPIDSNARK_DIR}/bin/${BINARY_NAME}" "$BUNDLE_DIR/" + + tar -czf "${BUNDLE_NAME}.tar.gz" "${BUNDLE_NAME}" + + - name: Bundle Rapidsnark Verifier + env: + BINARY_NAME: verifier + BUNDLE_NAME: verifier-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }} + RAPIDSNARK_DIR: circom_circuits/rapidsnark/package_macos_arm64 + run: | + BUNDLE_DIR="${BUNDLE_NAME}/${BINARY_NAME}" + mkdir -p "$BUNDLE_DIR" + + mv "${RAPIDSNARK_DIR}/bin/${BINARY_NAME}" "$BUNDLE_DIR/" + + tar -czf "${BUNDLE_NAME}.tar.gz" "${BUNDLE_NAME}" + + - name: Upload Rapidsnark Prover + uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 + with: + name: prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz + path: prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz + + - name: Upload Rapidsnark Verifier + uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 + with: + name: verifier-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz + path: verifier-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz + + - name: Compile and Bundle PoL + uses: ./.github/actions/compile-and-bundle + with: + circuit-name-display: "PoL" + circuit-name-binary: "pol" + circuit-path: "circom_circuits/Mantle/pol.circom" + version: ${{ env.VERSION }} + os: ${{ env.OS }} + arch: ${{ env.ARCH }} + + - name: Compile and Bundle PoQ + uses: ./.github/actions/compile-and-bundle + with: + circuit-name-display: "PoQ" + circuit-name-binary: "poq" + circuit-path: "circom_circuits/Blend/poq.circom" + version: ${{ env.VERSION }} + os: ${{ env.OS }} + arch: ${{ env.ARCH }} + + - name: Compile and Bundle ZKSign + uses: ./.github/actions/compile-and-bundle + with: + circuit-name-display: "ZKSign" + circuit-name-binary: "zksign" + circuit-path: "circom_circuits/Mantle/signature.circom" + version: ${{ env.VERSION }} + os: ${{ env.OS }} + arch: ${{ env.ARCH }} + + - name: Compile and Bundle PoC + uses: ./.github/actions/compile-and-bundle + with: + circuit-name-display: "PoC" + circuit-name-binary: "poc" + circuit-path: "circom_circuits/Mantle/poc.circom" + version: ${{ env.VERSION }} + os: ${{ env.OS }} + arch: ${{ env.ARCH }} + + publish-release: + name: Create Release + runs-on: ubuntu-latest + needs: + - setup + - build-linux + - build-windows + - build-macos + env: + TAG: ${{ needs.setup.outputs.tag }} + VERSION: ${{ needs.setup.outputs.version }} + outputs: + upload_url: ${{ steps.create_release.outputs.upload_url }} + steps: + - name: Create Release + uses: actions/create-release@4c11c9fe1dcd9636620a16455165783b20fc7ea0 + id: create_release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ env.TAG }} + release_name: Circom Circuits ${{ env.VERSION }} + body: | + This is a release of Circom Circuits ${{ 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: aarch64 + - os: windows + arch: x86_64 + artifact: + - prover + - verifier + - pol + - poq + - zksign + - poc + env: + UPLOAD_URL: ${{ needs.publish-release.outputs.upload_url }} + ARTIFACT_NAME: ${{ matrix.artifact }}-${{ needs.setup.outputs.version }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}.tar.gz + steps: + - name: Download Artifacts + uses: actions/download-artifact@448e3f862ab3ef47aa50ff917776823c9946035b + with: + name: ${{ env.ARTIFACT_NAME }} + + - name: Upload Artifacts to Release + uses: actions/upload-release-asset@ef2adfe8cb8ebfa540930c452c576b3819990faa + 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 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..bd9bd13 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "circomlib"] + path = circom_circuits/circomlib + url = https://github.com/iden3/circomlib.git +[submodule "rapidsnark"] + path = circom_circuits/rapidsnark + url = https://github.com/iden3/rapidsnark diff --git a/blend/generate_inputs_for_poq.py b/blend/generate_inputs_for_poq.py new file mode 100644 index 0000000..714e152 --- /dev/null +++ b/blend/generate_inputs_for_poq.py @@ -0,0 +1,331 @@ + + + +from sage.all import * + +p = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +F = FiniteField(p) + +def poseidon2_hash(data): + return PoseidonSponge(data,2,1)[0] + + + +def Poseidon2_sponge_hash_rate_1(data, n): + return PoseidonSponge(data,3,2,n,1) + +def Poseidon2_sponge_hash_rate_2(data, n): + return PoseidonSponge(data,3,1,n,1) + + +def SBox(inp): + return inp**5 + +def InternalRound(inp, i): + round_consts = [ + 0x1a1d063e54b1e764b63e1855bff015b8cedd192f47308731499573f23597d4b5, + 0x26abc66f3fdf8e68839d10956259063708235dccc1aa3793b91b002c5b257c37, + 0x0c7c64a9d887385381a578cfed5aed370754427aabca92a70b3c2b12ff4d7be8, + 0x1cf5998769e9fab79e17f0b6d08b2d1eba2ebac30dc386b0edd383831354b495, + 0x0f5e3a8566be31b7564ca60461e9e08b19828764a9669bc17aba0b97e66b0109, + 0x18df6a9d19ea90d895e60e4db0794a01f359a53a180b7d4b42bf3d7a531c976e, + 0x04f7bf2c5c0538ac6e4b782c3c6e601ad0ea1d3a3b9d25ef4e324055fa3123dc, + 0x29c76ce22255206e3c40058523748531e770c0584aa2328ce55d54628b89ebe6, + 0x198d425a45b78e85c053659ab4347f5d65b1b8e9c6108dbe00e0e945dbc5ff15, + 0x25ee27ab6296cd5e6af3cc79c598a1daa7ff7f6878b3c49d49d3a9a90c3fdf74, + 0x138ea8e0af41a1e024561001c0b6eb1505845d7d0c55b1b2c0f88687a96d1381, + 0x306197fb3fab671ef6e7c2cba2eefd0e42851b5b9811f2ca4013370a01d95687, + 0x1a0c7d52dc32a4432b66f0b4894d4f1a21db7565e5b4250486419eaf00e8f620, + 0x2b46b418de80915f3ff86a8e5c8bdfccebfbe5f55163cd6caa52997da2c54a9f, + 0x12d3e0dc0085873701f8b777b9673af9613a1af5db48e05bfb46e312b5829f64, + 0x263390cf74dc3a8870f5002ed21d089ffb2bf768230f648dba338a5cb19b3a1f, + 0x0a14f33a5fe668a60ac884b4ca607ad0f8abb5af40f96f1d7d543db52b003dcd, + 0x28ead9c586513eab1a5e86509d68b2da27be3a4f01171a1dd847df829bc683b9, + 0x1c6ab1c328c3c6430972031f1bdb2ac9888f0ea1abe71cffea16cda6e1a7416c, + 0x1fc7e71bc0b819792b2500239f7f8de04f6decd608cb98a932346015c5b42c94, + 0x03e107eb3a42b2ece380e0d860298f17c0c1e197c952650ee6dd85b93a0ddaa8, + 0x2d354a251f381a4669c0d52bf88b772c46452ca57c08697f454505f6941d78cd, + 0x094af88ab05d94baf687ef14bc566d1c522551d61606eda3d14b4606826f794b, + 0x19705b783bf3d2dc19bcaeabf02f8ca5e1ab5b6f2e3195a9d52b2d249d1396f7, + 0x09bf4acc3a8bce3f1fcc33fee54fc5b28723b16b7d740a3e60cef6852271200e, + 0x1803f8200db6013c50f83c0c8fab62843413732f301f7058543a073f3f3b5e4e, + 0x0f80afb5046244de30595b160b8d1f38bf6fb02d4454c0add41f7fef2faf3e5c, + 0x126ee1f8504f15c3d77f0088c1cfc964abcfcf643f4a6fea7dc3f98219529d78, + 0x23c203d10cfcc60f69bfb3d919552ca10ffb4ee63175ddf8ef86f991d7d0a591, + 0x2a2ae15d8b143709ec0d09705fa3a6303dec1ee4eec2cf747c5a339f7744fb94, + 0x07b60dee586ed6ef47e5c381ab6343ecc3d3b3006cb461bbb6b5d89081970b2b, + 0x27316b559be3edfd885d95c494c1ae3d8a98a320baa7d152132cfe583c9311bd, + 0x1d5c49ba157c32b8d8937cb2d3f84311ef834cc2a743ed662f5f9af0c0342e76, + 0x2f8b124e78163b2f332774e0b850b5ec09c01bf6979938f67c24bd5940968488, + 0x1e6843a5457416b6dc5b7aa09a9ce21b1d4cba6554e51d84665f75260113b3d5, + 0x11cdf00a35f650c55fca25c9929c8ad9a68daf9ac6a189ab1f5bc79f21641d4b, + 0x21632de3d3bbc5e42ef36e588158d6d4608b2815c77355b7e82b5b9b7eb560bc, + 0x0de625758452efbd97b27025fbd245e0255ae48ef2a329e449d7b5c51c18498a, + 0x2ad253c053e75213e2febfd4d976cc01dd9e1e1c6f0fb6b09b09546ba0838098, + 0x1d6b169ed63872dc6ec7681ec39b3be93dd49cdd13c813b7d35702e38d60b077, + 0x1660b740a143664bb9127c4941b67fed0be3ea70a24d5568c3a54e706cfef7fe, + 0x0065a92d1de81f34114f4ca2deef76e0ceacdddb12cf879096a29f10376ccbfe, + 0x1f11f065202535987367f823da7d672c353ebe2ccbc4869bcf30d50a5871040d, + 0x26596f5c5dd5a5d1b437ce7b14a2c3dd3bd1d1a39b6759ba110852d17df0693e, + 0x16f49bc727e45a2f7bf3056efcf8b6d38539c4163a5f1e706743db15af91860f, + 0x1abe1deb45b3e3119954175efb331bf4568feaf7ea8b3dc5e1a4e7438dd39e5f, + 0x0e426ccab66984d1d8993a74ca548b779f5db92aaec5f102020d34aea15fba59, + 0x0e7c30c2e2e8957f4933bd1942053f1f0071684b902d534fa841924303f6a6c6, + 0x0812a017ca92cf0a1622708fc7edff1d6166ded6e3528ead4c76e1f31d3fc69d, + 0x21a5ade3df2bc1b5bba949d1db96040068afe5026edd7a9c2e276b47cf010d54, + 0x01f3035463816c84ad711bf1a058c6c6bd101945f50e5afe72b1a5233f8749ce, + 0x0b115572f038c0e2028c2aafc2d06a5e8bf2f9398dbd0fdf4dcaa82b0f0c1c8b, + 0x1c38ec0b99b62fd4f0ef255543f50d2e27fc24db42bc910a3460613b6ef59e2f, + 0x1c89c6d9666272e8425c3ff1f4ac737b2f5d314606a297d4b1d0b254d880c53e, + 0x03326e643580356bf6d44008ae4c042a21ad4880097a5eb38b71e2311bb88f8f, + 0x268076b0054fb73f67cee9ea0e51e3ad50f27a6434b5dceb5bdde2299910a4c9, +] + + + sb = SBox(inp[0] + round_consts[i]) + out = [F(0) for i in range(3)] + out[0] = 2*sb + inp[1] + inp[2]; + out[1] = sb + 2*inp[1] + inp[2]; + out[2] = sb + inp[1] + 3*inp[2]; + return out + +def ExternalRound(inp, i): + out = [F(0) for j in range(3)] + round_consts = [ [F(0x1d066a255517b7fd8bddd3a93f7804ef7f8fcde48bb4c37a59a09a1a97052816) + , F(0x29daefb55f6f2dc6ac3f089cebcc6120b7c6fef31367b68eb7238547d32c1610) + , F(0x1f2cb1624a78ee001ecbd88ad959d7012572d76f08ec5c4f9e8b7ad7b0b4e1d1) + ] + , [ F(0x0aad2e79f15735f2bd77c0ed3d14aa27b11f092a53bbc6e1db0672ded84f31e5) + , F(0x2252624f8617738cd6f661dd4094375f37028a98f1dece66091ccf1595b43f28) + , F(0x1a24913a928b38485a65a84a291da1ff91c20626524b2b87d49f4f2c9018d735) + ] + , [ F(0x22fc468f1759b74d7bfc427b5f11ebb10a41515ddff497b14fd6dae1508fc47a) + , F(0x1059ca787f1f89ed9cd026e9c9ca107ae61956ff0b4121d5efd65515617f6e4d) + , F(0x02be9473358461d8f61f3536d877de982123011f0bf6f155a45cbbfae8b981ce) + ] + , [ F(0x0ec96c8e32962d462778a749c82ed623aba9b669ac5b8736a1ff3a441a5084a4) + , F(0x292f906e073677405442d9553c45fa3f5a47a7cdb8c99f9648fb2e4d814df57e) + , F(0x274982444157b86726c11b9a0f5e39a5cc611160a394ea460c63f0b2ffe5657e) + ] + , [ F(0x1acd63c67fbc9ab1626ed93491bda32e5da18ea9d8e4f10178d04aa6f8747ad0) + , F(0x19f8a5d670e8ab66c4e3144be58ef6901bf93375e2323ec3ca8c86cd2a28b5a5) + , F(0x1c0dc443519ad7a86efa40d2df10a011068193ea51f6c92ae1cfbb5f7b9b6893) + ] + , [ F(0x14b39e7aa4068dbe50fe7190e421dc19fbeab33cb4f6a2c4180e4c3224987d3d) + , F(0x1d449b71bd826ec58f28c63ea6c561b7b820fc519f01f021afb1e35e28b0795e) + , F(0x1ea2c9a89baaddbb60fa97fe60fe9d8e89de141689d1252276524dc0a9e987fc) + ] + , [ F(0x0478d66d43535a8cb57e9c1c3d6a2bd7591f9a46a0e9c058134d5cefdb3c7ff1) + , F(0x19272db71eece6a6f608f3b2717f9cd2662e26ad86c400b21cde5e4a7b00bebe) + , F(0x14226537335cab33c749c746f09208abb2dd1bd66a87ef75039be846af134166) + ] + , [ F(0x01fd6af15956294f9dfe38c0d976a088b21c21e4a1c2e823f912f44961f9a9ce) + , F(0x18e5abedd626ec307bca190b8b2cab1aaee2e62ed229ba5a5ad8518d4e5f2a57) + , F(0x0fc1bbceba0590f5abbdffa6d3b35e3297c021a3a409926d0e2d54dc1c84fda6) + ]] + + + sb = [F(0) for j in range(3)] + for j in range(3): + sb[j] = SBox(F(inp[j] + round_consts[i][j])) + out = [F(0) for j in range(3)] + out[0] = 2*sb[0] + sb[1] + sb[2] + out[1] = sb[0] + 2*sb[1] + sb[2] + out[2] = sb[0]+ sb[1] + 2*sb[2] + return out + +def LinearLayer(inp): + out = [F(0) for i in range(3)] + out[0] = 2*inp[0] + inp[1] + inp[2] + out[1] = inp[0] + 2*inp[1] + inp[2] + out[2] = inp[0] + inp[1] + 2*inp[2] + return out + +def Permutation(inp): + out = [F(0) for i in range(3)] + + state = LinearLayer(inp) + + for k in range(4): + state = ExternalRound(state, k) + for k in range(56): + state = InternalRound(state, k) + for k in range(4): + state = ExternalRound(state, k+4) + return state + +def Compression(inp): + return Permutation([inp[0],inp[1],F(0)]) + +def PoseidonSponge(data, capacity, output_len): + rate = 3 - capacity; + output = [F(0) for i in range(output_len)] + assert( capacity > 0 ) + assert( rate > 0 ) + assert( capacity < 3 ) + assert( rate < 3 ) + + # round up to rate the input + 1 field element ("10*" padding) + nblocks = ((len(data) + 1) + (rate-1)) // rate; + nout = (output_len + (rate-1)) // rate; + padded_len = nblocks * rate; + + padded = [] + for i in range(len(data)): + padded.append(F(data[i])) + padded.append(F(1)) + for i in range(len(data)+1,padded_len): + padded.append(F(0)) + + civ = F(0) + + state = [F(0),F(0),F(civ)] + sorbed = [F(0) for j in range(rate)] + + for m in range(nblocks): + for i in range(rate): + a = state[i] + b = padded[m*rate+i] + sorbed[i] = a + b + state = Permutation(sorbed[0:rate] + state[rate:3]) + + q = min(rate, output_len) + for i in range(q): + output[i] = state[i] + out_ptr = rate + + for n in range(1,nout): + state[nblocks+n] = Permutation(state[nblocks+n-1]) + q = min(rate, output_len-out_ptr) + for i in range(q): + output[out_ptr+i] = state[nblocks+n][i] + out_ptr += rate + + return output + +# ——————————————————————— +# Main +# ——————————————————————— +if len(sys.argv) != 5: + print("Usage: python3 generate_inputs_for_poq.py ") + sys.exit(1) + +session = int(sys.argv[1]) +Qc = int(sys.argv[2]) +Ql = int(sys.argv[3]) +core_or_leader = int(sys.argv[4]) +if not core_or_leader in [0,1]: + print("core or leader must be 0 or 1") + sys.exit(1) + +# 1) Core‐node registry Merkle‐proof +# pick a random core_sk and derive its public key +core_sk = F(randrange(0,p,1)) +pk_core = poseidon2_hash([ F(1296193216988918402894), core_sk ]) +core_selectors = randrange(0,2**20,1) +core_selectors = format(int(core_selectors),'020b') +core_nodes = [F(randrange(0,p,1)) for i in range(20)] +core_root = pk_core +for i in range(20): + if int(core_selectors[19-i]) == 0: + core_root = poseidon2_hash([core_root,core_nodes[i]]) + else: + core_root = poseidon2_hash([core_nodes[i],core_root]) + +#pk_root, core_path, core_selectors = merkle_root_and_path(pk_core, 20) + +# 2) PoL inputs (broadened from pol script) +epoch_nonce = F(randrange(0, p,1)) +slot_number = F(randrange(0, 2**32,1)) +total_stake = int(5000) + +t0_constant = F(0x1a3fb997fd58374772808c13d1c2ddacb5ab3ea77413f86fd6e0d3d978e5438) +t1_constant = F(0x71e790b41991052e30c93934b5612412e7958837bac8b1c524c24d84cc7d0) + +t0 = F(int(t0_constant) // total_stake) +t1 = F(p- (int(t1_constant) // total_stake**2)) + +value = F(total_stake / 100) +threshold = (t0 + t1 * value) * value +starting_slot = randrange(max(0,slot_number-2**25+1),slot_number,1) + +slot_secret = F(randrange(0,p,1)) +slot_secret_indexes = format(int(slot_number - starting_slot),'025b') + +tx_hash = F(randrange(0,p,1)) +output_number = F(randrange(0,50,1)) + + +slot_secret_path = [F(randrange(0,p,1)) for i in range(25)] +secret_root = slot_secret +for i in range(25): + if int(slot_secret_indexes[24-i]) == 0: + secret_root = poseidon2_hash([secret_root,slot_secret_path[i]]) + else: + secret_root = poseidon2_hash([slot_secret_path[i],secret_root]) +sk = poseidon2_hash([F(256174383281726064679014503048630094),starting_slot,secret_root]) +pk = poseidon2_hash([F(1296193216988918402894),sk]) + +note_id = poseidon2_hash([F(65580641562429851895355409762135920462),tx_hash,output_number,value,pk]) +ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk]) +while(ticket > threshold): + output_number += 1 + note_id = poseidon2_hash([F(65580641562429851895355409762135920462),tx_hash,output_number,value,pk]) + ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk]) + +aged_nodes = [F(randrange(0,p,1)) for i in range(32)] +aged_selectors = randrange(0,2**32,1) +aged_selectors = format(aged_selectors,'032b') +aged_root = note_id +for i in range(32): + if int(aged_selectors[31-i]) == 0: + aged_root = poseidon2_hash([aged_root,aged_nodes[i]]) + else: + aged_root = poseidon2_hash([aged_nodes[i],aged_root]) + +# 3) Choose branch & index +index = randrange(0, Ql if core_or_leader else Qc,1) + +# 4) One‐time key +K_one = F(123456) +K_two = F(654321) + +# 5) Assemble JSON +inp = { + "session": str(session), + "core_quota": str(Qc), + "leader_quota": str(Ql), + "core_root": str(core_root), + "pol_ledger_aged": str(aged_root), + "K_part_one": str(K_one), + "K_part_two": str(K_two), + "selector": str(core_or_leader), + "index": str(index), + "core_sk": str(core_sk), + "core_path": [str(x) for x in core_nodes], + "core_path_selectors": [str(x) for x in core_selectors], + "pol_sl": str(slot_number), + "pol_epoch_nonce": str(epoch_nonce), + "pol_t0": str(t0), + "pol_t1": str(t1), + "pol_slot_secret": str(slot_secret), + "pol_slot_secret_path": [str(x) for x in slot_secret_path], + "pol_noteid_path": [str(x) for x in aged_nodes], + "pol_noteid_path_selectors": [str(x) for x in aged_selectors], + "pol_note_tx_hash": str(tx_hash), + "pol_note_output_number": str(output_number), + "pol_sk_starting_slot": str(starting_slot), + "pol_note_value": str(value) +} + +if core_or_leader == 0: + inp["pol_ledger_aged"] = str(randrange(0,p,1)) +else: + inp["core_root"] = str(randrange(0,p,1)) + +import json + +with open("input.json","w") as f: + json.dump(inp, f, indent=2) + +print("Wrote input_poq.json") \ No newline at end of file diff --git a/blend/poq.circom b/blend/poq.circom new file mode 100644 index 0000000..86c82c0 --- /dev/null +++ b/blend/poq.circom @@ -0,0 +1,137 @@ +// PoQ.circom +pragma circom 2.1.9; + +include "../hash_bn/poseidon2_hash.circom"; +include "../misc/constants.circom"; // defines NOMOS_KDF, SELECTION_RANDOMNESS, PROOF_NULLIFIER +include "../misc/comparator.circom"; +include "../circomlib/circuits/bitify.circom"; +include "../Mantle/pol_lib.circom"; // defines proof_of_leadership +include "../ledger/notes.circom"; + +/** + * ProofOfQuota(nLevelsPK, nLevelsPol) + * + * - nLevelsPK : depth of the core-node public-key registry Merkle tree + * - nLevelsPol : depth of the slot-secret tree used in PoL (25) + * - bitsQuota : bit-width for the index comparator + */ +template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) { + // Public Inputs + signal input session; // session s + signal input core_quota; + signal input leader_quota; + signal input core_root; + signal input pol_ledger_aged; // PoL: aged notes root + signal input K_part_one; // Blend: one-time signature public key + signal input K_part_two; // Blend: one-time signature public key + + + // dummy constraints to avoid unused public input to be erased after compilation optimisation + signal dummy_one; + dummy_one <== K_part_one * K_part_one; + signal dummy_two; + dummy_two <== K_part_two * K_part_two; + + signal output key_nullifier; //key_nullifier + + // Private Inputs + signal input selector; // 0 = core, 1 = leader + signal input index; // nullifier index + + // Core-nodes inputs + signal input core_sk; // core node secret key + signal input core_path[nLevelsPK]; // Merkle path for core PK + signal input core_path_selectors[nLevelsPK]; // path selectors (bits) + + // PoL branch inputs (all the PoL private data) + signal input pol_sl; + signal input pol_epoch_nonce; + signal input pol_t0; + signal input pol_t1; + signal input pol_slot_secret; + signal input pol_slot_secret_path[nLevelsPol]; + + signal input pol_noteid_path[32]; + signal input pol_noteid_path_selectors[32]; + signal input pol_note_tx_hash; + signal input pol_note_output_number; + + signal input pol_sk_starting_slot; + signal input pol_note_value; + + + // Constraint the selector to be a bit + selector * (1 - selector) === 0; + + + // Quota check: index < core_quota if core, index < leader_quota if leader + component cmp = SafeLessThan(bitsQuota); + cmp.in[0] <== index; + cmp.in[1] <== selector * (leader_quota - core_quota) + core_quota; + cmp.out === 1; + + + // derive zk_id + component zk_id = derive_public_key(); + zk_id.secret_key <== core_sk; + + + // Merkle‐verify zk_id in core_root + component is_registered = proof_of_membership(nLevelsPK); + for (var i = 0; i < nLevelsPK; i++) { + //check that the selectors are indeed bits + core_path_selectors[i] * (1 - core_path_selectors[i]) === 0; + //call the merkle proof checker + is_registered.nodes[i] <== core_path[i]; + is_registered.selector[i] <== core_path_selectors[i]; + } + is_registered.root <== core_root; + is_registered.leaf <== zk_id.out; + + + // enforce potential PoL (without verification that the note is unspent) + // (All constraints inside pol ensure LeadershipVerify) + component would_win = would_win_leadership(nLevelsPol); + would_win.slot <== pol_sl; + would_win.epoch_nonce <== pol_epoch_nonce; + would_win.t0 <== pol_t0; + would_win.t1 <== pol_t1; + would_win.slot_secret <== pol_slot_secret; + for (var i = 0; i < nLevelsPol; i++) { + would_win.slot_secret_path[i] <== pol_slot_secret_path[i]; + } + for (var i = 0; i < 32; i++) { + would_win.aged_nodes[i] <== pol_noteid_path[i]; + would_win.aged_selectors[i] <== pol_noteid_path_selectors[i]; + } + would_win.aged_root <== pol_ledger_aged; + would_win.transaction_hash <== pol_note_tx_hash; + would_win.output_number <== pol_note_output_number; + would_win.starting_slot <== pol_sk_starting_slot; + would_win.value <== pol_note_value; + + // Enforce the selected role is correct + selector * (would_win.out - is_registered.out) + is_registered.out === 1; + + + // Derive selection_randomness + component selection_randomness = Poseidon2_hash(4); + component dstSel = SELECTION_RANDOMNESS_V1(); + selection_randomness.inp[0] <== dstSel.out; + // choose core_sk or pol.secret_key: + selection_randomness.inp[1] <== selector * (would_win.secret_key - core_sk ) + core_sk; + selection_randomness.inp[2] <== index; + selection_randomness.inp[3] <== session; + + + // Derive key_nullifier + component nf = Poseidon2_hash(2); + component dstNF = KEY_NULLIFIER_V1(); + nf.inp[0] <== dstNF.out; + nf.inp[1] <== selection_randomness.out; + key_nullifier <== nf.out; +} + +// Instantiate with chosen depths: 20 for core PK tree, 25 for PoL secret slot tree +component main { public [ session, core_quota, leader_quota, core_root, K_part_one, K_part_two, pol_epoch_nonce, pol_t0, pol_t1, pol_ledger_aged ] } + = ProofOfQuota(20, 25, 20); diff --git a/hash_bn/merkle.circom b/hash_bn/merkle.circom new file mode 100644 index 0000000..4bc5273 --- /dev/null +++ b/hash_bn/merkle.circom @@ -0,0 +1,55 @@ +//test +pragma circom 2.1.9; + +include "../hash_bn/poseidon2_hash.circom"; +include "../circomlib/circuits/comparators.circom"; + +// compute a merkle root of depth n +// /!\ To call this function, it's important to check that each selector is a bit before!!! +template compute_merkle_root(n) { + signal input nodes[n]; // The Merkle path + signal input selector[n]; // it's the leaf's indice in big endian bits indicating if complementary nodes are left or right + signal input leaf; + signal output root; + + + component compression_hash[n]; + + compression_hash[0] = Poseidon2_hash(2); + compression_hash[0].inp[0] <== leaf - selector[n-1] * (leaf - nodes[0]); + compression_hash[0].inp[1] <== nodes[0] - selector[n-1] * (nodes[0] - leaf); + + for(var i=1; i out; +} + +//------------------------------------------------------------------------------ \ No newline at end of file diff --git a/hash_bn/poseidon2_perm.circom b/hash_bn/poseidon2_perm.circom new file mode 100644 index 0000000..c68b792 --- /dev/null +++ b/hash_bn/poseidon2_perm.circom @@ -0,0 +1,217 @@ +// +pragma circom 2.1.9; + +// +// The Poseidon2 permutation for bn128 and t=3 +// + +//------------------------------------------------------------------------------ +// The S-box + +template SBox() { + signal input inp; + signal output out; + + signal x2 <== inp*inp; + signal x4 <== x2*x2; + + out <== inp*x4; +} + +//------------------------------------------------------------------------------ +// partial or internal round + +template InternalRound(i) { + signal input inp[3]; + signal output out[3]; + + var round_consts[56] = + [0x1a1d063e54b1e764b63e1855bff015b8cedd192f47308731499573f23597d4b5, + 0x26abc66f3fdf8e68839d10956259063708235dccc1aa3793b91b002c5b257c37, + 0x0c7c64a9d887385381a578cfed5aed370754427aabca92a70b3c2b12ff4d7be8, + 0x1cf5998769e9fab79e17f0b6d08b2d1eba2ebac30dc386b0edd383831354b495, + 0x0f5e3a8566be31b7564ca60461e9e08b19828764a9669bc17aba0b97e66b0109, + 0x18df6a9d19ea90d895e60e4db0794a01f359a53a180b7d4b42bf3d7a531c976e, + 0x04f7bf2c5c0538ac6e4b782c3c6e601ad0ea1d3a3b9d25ef4e324055fa3123dc, + 0x29c76ce22255206e3c40058523748531e770c0584aa2328ce55d54628b89ebe6, + 0x198d425a45b78e85c053659ab4347f5d65b1b8e9c6108dbe00e0e945dbc5ff15, + 0x25ee27ab6296cd5e6af3cc79c598a1daa7ff7f6878b3c49d49d3a9a90c3fdf74, + 0x138ea8e0af41a1e024561001c0b6eb1505845d7d0c55b1b2c0f88687a96d1381, + 0x306197fb3fab671ef6e7c2cba2eefd0e42851b5b9811f2ca4013370a01d95687, + 0x1a0c7d52dc32a4432b66f0b4894d4f1a21db7565e5b4250486419eaf00e8f620, + 0x2b46b418de80915f3ff86a8e5c8bdfccebfbe5f55163cd6caa52997da2c54a9f, + 0x12d3e0dc0085873701f8b777b9673af9613a1af5db48e05bfb46e312b5829f64, + 0x263390cf74dc3a8870f5002ed21d089ffb2bf768230f648dba338a5cb19b3a1f, + 0x0a14f33a5fe668a60ac884b4ca607ad0f8abb5af40f96f1d7d543db52b003dcd, + 0x28ead9c586513eab1a5e86509d68b2da27be3a4f01171a1dd847df829bc683b9, + 0x1c6ab1c328c3c6430972031f1bdb2ac9888f0ea1abe71cffea16cda6e1a7416c, + 0x1fc7e71bc0b819792b2500239f7f8de04f6decd608cb98a932346015c5b42c94, + 0x03e107eb3a42b2ece380e0d860298f17c0c1e197c952650ee6dd85b93a0ddaa8, + 0x2d354a251f381a4669c0d52bf88b772c46452ca57c08697f454505f6941d78cd, + 0x094af88ab05d94baf687ef14bc566d1c522551d61606eda3d14b4606826f794b, + 0x19705b783bf3d2dc19bcaeabf02f8ca5e1ab5b6f2e3195a9d52b2d249d1396f7, + 0x09bf4acc3a8bce3f1fcc33fee54fc5b28723b16b7d740a3e60cef6852271200e, + 0x1803f8200db6013c50f83c0c8fab62843413732f301f7058543a073f3f3b5e4e, + 0x0f80afb5046244de30595b160b8d1f38bf6fb02d4454c0add41f7fef2faf3e5c, + 0x126ee1f8504f15c3d77f0088c1cfc964abcfcf643f4a6fea7dc3f98219529d78, + 0x23c203d10cfcc60f69bfb3d919552ca10ffb4ee63175ddf8ef86f991d7d0a591, + 0x2a2ae15d8b143709ec0d09705fa3a6303dec1ee4eec2cf747c5a339f7744fb94, + 0x07b60dee586ed6ef47e5c381ab6343ecc3d3b3006cb461bbb6b5d89081970b2b, + 0x27316b559be3edfd885d95c494c1ae3d8a98a320baa7d152132cfe583c9311bd, + 0x1d5c49ba157c32b8d8937cb2d3f84311ef834cc2a743ed662f5f9af0c0342e76, + 0x2f8b124e78163b2f332774e0b850b5ec09c01bf6979938f67c24bd5940968488, + 0x1e6843a5457416b6dc5b7aa09a9ce21b1d4cba6554e51d84665f75260113b3d5, + 0x11cdf00a35f650c55fca25c9929c8ad9a68daf9ac6a189ab1f5bc79f21641d4b, + 0x21632de3d3bbc5e42ef36e588158d6d4608b2815c77355b7e82b5b9b7eb560bc, + 0x0de625758452efbd97b27025fbd245e0255ae48ef2a329e449d7b5c51c18498a, + 0x2ad253c053e75213e2febfd4d976cc01dd9e1e1c6f0fb6b09b09546ba0838098, + 0x1d6b169ed63872dc6ec7681ec39b3be93dd49cdd13c813b7d35702e38d60b077, + 0x1660b740a143664bb9127c4941b67fed0be3ea70a24d5568c3a54e706cfef7fe, + 0x0065a92d1de81f34114f4ca2deef76e0ceacdddb12cf879096a29f10376ccbfe, + 0x1f11f065202535987367f823da7d672c353ebe2ccbc4869bcf30d50a5871040d, + 0x26596f5c5dd5a5d1b437ce7b14a2c3dd3bd1d1a39b6759ba110852d17df0693e, + 0x16f49bc727e45a2f7bf3056efcf8b6d38539c4163a5f1e706743db15af91860f, + 0x1abe1deb45b3e3119954175efb331bf4568feaf7ea8b3dc5e1a4e7438dd39e5f, + 0x0e426ccab66984d1d8993a74ca548b779f5db92aaec5f102020d34aea15fba59, + 0x0e7c30c2e2e8957f4933bd1942053f1f0071684b902d534fa841924303f6a6c6, + 0x0812a017ca92cf0a1622708fc7edff1d6166ded6e3528ead4c76e1f31d3fc69d, + 0x21a5ade3df2bc1b5bba949d1db96040068afe5026edd7a9c2e276b47cf010d54, + 0x01f3035463816c84ad711bf1a058c6c6bd101945f50e5afe72b1a5233f8749ce, + 0x0b115572f038c0e2028c2aafc2d06a5e8bf2f9398dbd0fdf4dcaa82b0f0c1c8b, + 0x1c38ec0b99b62fd4f0ef255543f50d2e27fc24db42bc910a3460613b6ef59e2f, + 0x1c89c6d9666272e8425c3ff1f4ac737b2f5d314606a297d4b1d0b254d880c53e, + 0x03326e643580356bf6d44008ae4c042a21ad4880097a5eb38b71e2311bb88f8f, + 0x268076b0054fb73f67cee9ea0e51e3ad50f27a6434b5dceb5bdde2299910a4c9]; + + component sb = SBox(); + sb.inp <== inp[0] + round_consts[i]; + + out[0] <== 2*sb.out + inp[1] + inp[2]; + out[1] <== sb.out + 2*inp[1] + inp[2]; + out[2] <== sb.out + inp[1] + 3*inp[2]; + +} + +//------------------------------------------------------------------------------ +// external rounds + +template ExternalRound(i) { + signal input inp[3]; + signal output out[3]; + + var round_consts[8][3] = + + [ [ 0x1d066a255517b7fd8bddd3a93f7804ef7f8fcde48bb4c37a59a09a1a97052816 + , 0x29daefb55f6f2dc6ac3f089cebcc6120b7c6fef31367b68eb7238547d32c1610 + , 0x1f2cb1624a78ee001ecbd88ad959d7012572d76f08ec5c4f9e8b7ad7b0b4e1d1 + ] + , [ 0x0aad2e79f15735f2bd77c0ed3d14aa27b11f092a53bbc6e1db0672ded84f31e5 + , 0x2252624f8617738cd6f661dd4094375f37028a98f1dece66091ccf1595b43f28 + , 0x1a24913a928b38485a65a84a291da1ff91c20626524b2b87d49f4f2c9018d735 + ] + , [ 0x22fc468f1759b74d7bfc427b5f11ebb10a41515ddff497b14fd6dae1508fc47a + , 0x1059ca787f1f89ed9cd026e9c9ca107ae61956ff0b4121d5efd65515617f6e4d + , 0x02be9473358461d8f61f3536d877de982123011f0bf6f155a45cbbfae8b981ce + ] + , [ 0x0ec96c8e32962d462778a749c82ed623aba9b669ac5b8736a1ff3a441a5084a4 + , 0x292f906e073677405442d9553c45fa3f5a47a7cdb8c99f9648fb2e4d814df57e + , 0x274982444157b86726c11b9a0f5e39a5cc611160a394ea460c63f0b2ffe5657e + ] + , [ 0x1acd63c67fbc9ab1626ed93491bda32e5da18ea9d8e4f10178d04aa6f8747ad0 + , 0x19f8a5d670e8ab66c4e3144be58ef6901bf93375e2323ec3ca8c86cd2a28b5a5 + , 0x1c0dc443519ad7a86efa40d2df10a011068193ea51f6c92ae1cfbb5f7b9b6893 + ] + , [ 0x14b39e7aa4068dbe50fe7190e421dc19fbeab33cb4f6a2c4180e4c3224987d3d + , 0x1d449b71bd826ec58f28c63ea6c561b7b820fc519f01f021afb1e35e28b0795e + , 0x1ea2c9a89baaddbb60fa97fe60fe9d8e89de141689d1252276524dc0a9e987fc + ] + , [ 0x0478d66d43535a8cb57e9c1c3d6a2bd7591f9a46a0e9c058134d5cefdb3c7ff1 + , 0x19272db71eece6a6f608f3b2717f9cd2662e26ad86c400b21cde5e4a7b00bebe + , 0x14226537335cab33c749c746f09208abb2dd1bd66a87ef75039be846af134166 + ] + , [ 0x01fd6af15956294f9dfe38c0d976a088b21c21e4a1c2e823f912f44961f9a9ce + , 0x18e5abedd626ec307bca190b8b2cab1aaee2e62ed229ba5a5ad8518d4e5f2a57 + , 0x0fc1bbceba0590f5abbdffa6d3b35e3297c021a3a409926d0e2d54dc1c84fda6 + ] + ]; + + component sb[3]; + for(var j=0; j<3; j++) { + sb[j] = SBox(); + sb[j].inp <== inp[j] + round_consts[i][j]; + } + + out[0] <== 2*sb[0].out + sb[1].out + sb[2].out; + out[1] <== sb[0].out + 2*sb[1].out + sb[2].out; + out[2] <== sb[0].out + sb[1].out + 2*sb[2].out; +} + +//------------------------------------------------------------------------------ +// the initial linear layer + +template LinearLayer() { + signal input inp[3]; + signal output out[3]; + out[0] <== 2*inp[0] + inp[1] + inp[2]; + out[1] <== inp[0] + 2*inp[1] + inp[2]; + out[2] <== inp[0] + inp[1] + 2*inp[2]; +} + +//------------------------------------------------------------------------------ +// the Poseidon2 permutation for t=3 + +template Permutation() { + signal input inp[3]; + signal output out[3]; + + signal aux[65][3]; + + component ll = LinearLayer(); + for(var j=0; j<3; j++) { ll.inp[j] <== inp[j]; } + for(var j=0; j<3; j++) { ll.out[j] ==> aux[0][j]; } + + component ext[8]; + for(var k=0; k<8; k++) { ext[k] = ExternalRound(k); } + + component int[56]; + for(var k=0; k<56; k++) { int[k] = InternalRound(k); } + + // first 4 external rounds + for(var k=0; k<4; k++) { + for(var j=0; j<3; j++) { ext[k].inp[j] <== aux[k ][j]; } + for(var j=0; j<3; j++) { ext[k].out[j] ==> aux[k+1][j]; } + } + + // the 56 internal rounds + for(var k=0; k<56; k++) { + for(var j=0; j<3; j++) { int[k].inp[j] <== aux[k+4][j]; } + for(var j=0; j<3; j++) { int[k].out[j] ==> aux[k+5][j]; } + } + + // last 4 external rounds + for(var k=0; k<4; k++) { + for(var j=0; j<3; j++) { ext[k+4].inp[j] <== aux[k+60][j]; } + for(var j=0; j<3; j++) { ext[k+4].out[j] ==> aux[k+61][j]; } + } + + for(var j=0; j<3; j++) { out[j] <== aux[64][j]; } +} + +//------------------------------------------------------------------------------ +// the "compression function" takes 2 field elements as input and produces +// 1 field element as output. It is a trivial application of the permutation. + +template Compression() { + signal input inp[2]; + signal output out; + + component perm = Permutation(); + perm.inp[0] <== inp[0]; + perm.inp[1] <== inp[1]; + perm.inp[2] <== 0; + + perm.out[0] ==> out; +} + +//------------------------------------------------------------------------------ + diff --git a/hash_bn/poseidon2_sponge.circom b/hash_bn/poseidon2_sponge.circom new file mode 100644 index 0000000..ec71cab --- /dev/null +++ b/hash_bn/poseidon2_sponge.circom @@ -0,0 +1,123 @@ +// +pragma circom 2.1.9; + +include "poseidon2_perm.circom"; + +//------------------------------------------------------------------------------ + +function min(a,b) { + return (a <= b) ? a : b; +} + +//------------------------------------------------------------------------------ + +// +// Poseidon sponge construction +// +// t = size of state (currently fixed to 3) +// c = capacity (1 or 2) +// r = rate = t - c +// +// everything is measured in number of field elements +// +// we use the padding `10*` from the original Poseidon paper, +// and initial state constant zero. Note that this is different +// from the "SAFE padding" recommended in the Poseidon2 paper +// (which uses `0*` padding and a nontrivial initial state) +// + +template PoseidonSponge(t, capacity, input_len, output_len) { + + var rate = t - capacity; + + assert( t == 3); + + assert( capacity > 0 ); + assert( rate > 0 ); + assert( capacity < t ); + assert( rate < t ); + + signal input inp[ input_len]; + signal output out[output_len]; + + // round up to rate the input + 1 field element ("10*" padding) + var nblocks = ((input_len + 1) + (rate-1)) \ rate; + var nout = (output_len + (rate-1)) \ rate; + var padded_len = nblocks * rate; + + signal padded[padded_len]; + for(var i=0; i state[m+1]; + + } + + var q = min(rate, output_len); + for(var i=0; i out[i]; + } + var out_ptr = rate; + + for(var n=1; n state[nblocks+n ]; + + var q = min(rate, output_len-out_ptr); + for(var i=0; i out[out_ptr+i]; + } + out_ptr += rate; + } + +} + +//------------------------------------------------------------------------------ + +// +// sponge hash with rate=1 +// + +template Poseidon2_sponge_hash_rate_1(n) { + signal input inp[n]; + signal output out; + component sponge = PoseidonSponge(3, 2, n, 1); + sponge.inp <== inp; + sponge.out[0] ==> out; +} + +// +// sponge hash with rate=2 +// + +template Poseidon2_sponge_hash_rate_2(n) { + signal input inp[n]; + signal output out; + component sponge = PoseidonSponge(3, 1, n, 1); + sponge.inp <== inp; + sponge.out[0] ==> out; +} + +//------------------------------------------------------------------------------ diff --git a/ledger/notes.circom b/ledger/notes.circom new file mode 100644 index 0000000..3d34fe2 --- /dev/null +++ b/ledger/notes.circom @@ -0,0 +1,30 @@ +//test +pragma circom 2.1.9; + +include "../hash_bn/poseidon2_hash.circom"; +include "../misc/constants.circom"; + +template derive_secret_key(){ + signal input starting_slot; + signal input secrets_root; + signal output out; + + component hash = Poseidon2_hash(3); + component dst = NOMOS_POL_SK_V1(); + hash.inp[0] <== dst.out; + hash.inp[1] <== starting_slot; + hash.inp[2] <== secrets_root; + + out <== hash.out; +} + +template derive_public_key(){ + signal input secret_key; + signal output out; + + component hash = Poseidon2_hash(2); + component dst = NOMOS_KDF(); + hash.inp[0] <== dst.out; + hash.inp[1] <== secret_key; + out <== hash.out; +} \ No newline at end of file diff --git a/mantle/generate_inputs_for_pol.py b/mantle/generate_inputs_for_pol.py new file mode 100755 index 0000000..101fdeb --- /dev/null +++ b/mantle/generate_inputs_for_pol.py @@ -0,0 +1,308 @@ +#!/usr/bin/sage +# -*- mode: python ; -*- + + +from sage.all import * + +p = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +F = FiniteField(p) + +def poseidon2_hash(data): + return PoseidonSponge(data,2,1)[0] + + + +def Poseidon2_sponge_hash_rate_1(data, n): + return PoseidonSponge(data,3,2,n,1) + +def Poseidon2_sponge_hash_rate_2(data, n): + return PoseidonSponge(data,3,1,n,1) + + +def SBox(inp): + return inp**5 + +def InternalRound(inp, i): + round_consts = [ + 0x1a1d063e54b1e764b63e1855bff015b8cedd192f47308731499573f23597d4b5, + 0x26abc66f3fdf8e68839d10956259063708235dccc1aa3793b91b002c5b257c37, + 0x0c7c64a9d887385381a578cfed5aed370754427aabca92a70b3c2b12ff4d7be8, + 0x1cf5998769e9fab79e17f0b6d08b2d1eba2ebac30dc386b0edd383831354b495, + 0x0f5e3a8566be31b7564ca60461e9e08b19828764a9669bc17aba0b97e66b0109, + 0x18df6a9d19ea90d895e60e4db0794a01f359a53a180b7d4b42bf3d7a531c976e, + 0x04f7bf2c5c0538ac6e4b782c3c6e601ad0ea1d3a3b9d25ef4e324055fa3123dc, + 0x29c76ce22255206e3c40058523748531e770c0584aa2328ce55d54628b89ebe6, + 0x198d425a45b78e85c053659ab4347f5d65b1b8e9c6108dbe00e0e945dbc5ff15, + 0x25ee27ab6296cd5e6af3cc79c598a1daa7ff7f6878b3c49d49d3a9a90c3fdf74, + 0x138ea8e0af41a1e024561001c0b6eb1505845d7d0c55b1b2c0f88687a96d1381, + 0x306197fb3fab671ef6e7c2cba2eefd0e42851b5b9811f2ca4013370a01d95687, + 0x1a0c7d52dc32a4432b66f0b4894d4f1a21db7565e5b4250486419eaf00e8f620, + 0x2b46b418de80915f3ff86a8e5c8bdfccebfbe5f55163cd6caa52997da2c54a9f, + 0x12d3e0dc0085873701f8b777b9673af9613a1af5db48e05bfb46e312b5829f64, + 0x263390cf74dc3a8870f5002ed21d089ffb2bf768230f648dba338a5cb19b3a1f, + 0x0a14f33a5fe668a60ac884b4ca607ad0f8abb5af40f96f1d7d543db52b003dcd, + 0x28ead9c586513eab1a5e86509d68b2da27be3a4f01171a1dd847df829bc683b9, + 0x1c6ab1c328c3c6430972031f1bdb2ac9888f0ea1abe71cffea16cda6e1a7416c, + 0x1fc7e71bc0b819792b2500239f7f8de04f6decd608cb98a932346015c5b42c94, + 0x03e107eb3a42b2ece380e0d860298f17c0c1e197c952650ee6dd85b93a0ddaa8, + 0x2d354a251f381a4669c0d52bf88b772c46452ca57c08697f454505f6941d78cd, + 0x094af88ab05d94baf687ef14bc566d1c522551d61606eda3d14b4606826f794b, + 0x19705b783bf3d2dc19bcaeabf02f8ca5e1ab5b6f2e3195a9d52b2d249d1396f7, + 0x09bf4acc3a8bce3f1fcc33fee54fc5b28723b16b7d740a3e60cef6852271200e, + 0x1803f8200db6013c50f83c0c8fab62843413732f301f7058543a073f3f3b5e4e, + 0x0f80afb5046244de30595b160b8d1f38bf6fb02d4454c0add41f7fef2faf3e5c, + 0x126ee1f8504f15c3d77f0088c1cfc964abcfcf643f4a6fea7dc3f98219529d78, + 0x23c203d10cfcc60f69bfb3d919552ca10ffb4ee63175ddf8ef86f991d7d0a591, + 0x2a2ae15d8b143709ec0d09705fa3a6303dec1ee4eec2cf747c5a339f7744fb94, + 0x07b60dee586ed6ef47e5c381ab6343ecc3d3b3006cb461bbb6b5d89081970b2b, + 0x27316b559be3edfd885d95c494c1ae3d8a98a320baa7d152132cfe583c9311bd, + 0x1d5c49ba157c32b8d8937cb2d3f84311ef834cc2a743ed662f5f9af0c0342e76, + 0x2f8b124e78163b2f332774e0b850b5ec09c01bf6979938f67c24bd5940968488, + 0x1e6843a5457416b6dc5b7aa09a9ce21b1d4cba6554e51d84665f75260113b3d5, + 0x11cdf00a35f650c55fca25c9929c8ad9a68daf9ac6a189ab1f5bc79f21641d4b, + 0x21632de3d3bbc5e42ef36e588158d6d4608b2815c77355b7e82b5b9b7eb560bc, + 0x0de625758452efbd97b27025fbd245e0255ae48ef2a329e449d7b5c51c18498a, + 0x2ad253c053e75213e2febfd4d976cc01dd9e1e1c6f0fb6b09b09546ba0838098, + 0x1d6b169ed63872dc6ec7681ec39b3be93dd49cdd13c813b7d35702e38d60b077, + 0x1660b740a143664bb9127c4941b67fed0be3ea70a24d5568c3a54e706cfef7fe, + 0x0065a92d1de81f34114f4ca2deef76e0ceacdddb12cf879096a29f10376ccbfe, + 0x1f11f065202535987367f823da7d672c353ebe2ccbc4869bcf30d50a5871040d, + 0x26596f5c5dd5a5d1b437ce7b14a2c3dd3bd1d1a39b6759ba110852d17df0693e, + 0x16f49bc727e45a2f7bf3056efcf8b6d38539c4163a5f1e706743db15af91860f, + 0x1abe1deb45b3e3119954175efb331bf4568feaf7ea8b3dc5e1a4e7438dd39e5f, + 0x0e426ccab66984d1d8993a74ca548b779f5db92aaec5f102020d34aea15fba59, + 0x0e7c30c2e2e8957f4933bd1942053f1f0071684b902d534fa841924303f6a6c6, + 0x0812a017ca92cf0a1622708fc7edff1d6166ded6e3528ead4c76e1f31d3fc69d, + 0x21a5ade3df2bc1b5bba949d1db96040068afe5026edd7a9c2e276b47cf010d54, + 0x01f3035463816c84ad711bf1a058c6c6bd101945f50e5afe72b1a5233f8749ce, + 0x0b115572f038c0e2028c2aafc2d06a5e8bf2f9398dbd0fdf4dcaa82b0f0c1c8b, + 0x1c38ec0b99b62fd4f0ef255543f50d2e27fc24db42bc910a3460613b6ef59e2f, + 0x1c89c6d9666272e8425c3ff1f4ac737b2f5d314606a297d4b1d0b254d880c53e, + 0x03326e643580356bf6d44008ae4c042a21ad4880097a5eb38b71e2311bb88f8f, + 0x268076b0054fb73f67cee9ea0e51e3ad50f27a6434b5dceb5bdde2299910a4c9, +] + + + sb = SBox(inp[0] + round_consts[i]) + out = [F(0) for i in range(3)] + out[0] = 2*sb + inp[1] + inp[2]; + out[1] = sb + 2*inp[1] + inp[2]; + out[2] = sb + inp[1] + 3*inp[2]; + return out + +def ExternalRound(inp, i): + out = [F(0) for j in range(3)] + round_consts = [ [F(0x1d066a255517b7fd8bddd3a93f7804ef7f8fcde48bb4c37a59a09a1a97052816) + , F(0x29daefb55f6f2dc6ac3f089cebcc6120b7c6fef31367b68eb7238547d32c1610) + , F(0x1f2cb1624a78ee001ecbd88ad959d7012572d76f08ec5c4f9e8b7ad7b0b4e1d1) + ] + , [ F(0x0aad2e79f15735f2bd77c0ed3d14aa27b11f092a53bbc6e1db0672ded84f31e5) + , F(0x2252624f8617738cd6f661dd4094375f37028a98f1dece66091ccf1595b43f28) + , F(0x1a24913a928b38485a65a84a291da1ff91c20626524b2b87d49f4f2c9018d735) + ] + , [ F(0x22fc468f1759b74d7bfc427b5f11ebb10a41515ddff497b14fd6dae1508fc47a) + , F(0x1059ca787f1f89ed9cd026e9c9ca107ae61956ff0b4121d5efd65515617f6e4d) + , F(0x02be9473358461d8f61f3536d877de982123011f0bf6f155a45cbbfae8b981ce) + ] + , [ F(0x0ec96c8e32962d462778a749c82ed623aba9b669ac5b8736a1ff3a441a5084a4) + , F(0x292f906e073677405442d9553c45fa3f5a47a7cdb8c99f9648fb2e4d814df57e) + , F(0x274982444157b86726c11b9a0f5e39a5cc611160a394ea460c63f0b2ffe5657e) + ] + , [ F(0x1acd63c67fbc9ab1626ed93491bda32e5da18ea9d8e4f10178d04aa6f8747ad0) + , F(0x19f8a5d670e8ab66c4e3144be58ef6901bf93375e2323ec3ca8c86cd2a28b5a5) + , F(0x1c0dc443519ad7a86efa40d2df10a011068193ea51f6c92ae1cfbb5f7b9b6893) + ] + , [ F(0x14b39e7aa4068dbe50fe7190e421dc19fbeab33cb4f6a2c4180e4c3224987d3d) + , F(0x1d449b71bd826ec58f28c63ea6c561b7b820fc519f01f021afb1e35e28b0795e) + , F(0x1ea2c9a89baaddbb60fa97fe60fe9d8e89de141689d1252276524dc0a9e987fc) + ] + , [ F(0x0478d66d43535a8cb57e9c1c3d6a2bd7591f9a46a0e9c058134d5cefdb3c7ff1) + , F(0x19272db71eece6a6f608f3b2717f9cd2662e26ad86c400b21cde5e4a7b00bebe) + , F(0x14226537335cab33c749c746f09208abb2dd1bd66a87ef75039be846af134166) + ] + , [ F(0x01fd6af15956294f9dfe38c0d976a088b21c21e4a1c2e823f912f44961f9a9ce) + , F(0x18e5abedd626ec307bca190b8b2cab1aaee2e62ed229ba5a5ad8518d4e5f2a57) + , F(0x0fc1bbceba0590f5abbdffa6d3b35e3297c021a3a409926d0e2d54dc1c84fda6) + ]] + + sb = [F(0) for j in range(3)] + for j in range(3): + sb[j] = SBox(F(inp[j] + round_consts[i][j])) + out = [F(0) for j in range(3)] + out[0] = 2*sb[0] + sb[1] + sb[2] + out[1] = sb[0] + 2*sb[1] + sb[2] + out[2] = sb[0]+ sb[1] + 2*sb[2] + return out + +def LinearLayer(inp): + out = [F(0) for i in range(3)] + out[0] = 2*inp[0] + inp[1] + inp[2] + out[1] = inp[0] + 2*inp[1] + inp[2] + out[2] = inp[0] + inp[1] + 2*inp[2] + return out + +def Permutation(inp): + out = [F(0) for i in range(3)] + + state = LinearLayer(inp) + + for k in range(4): + state = ExternalRound(state, k) + for k in range(56): + state = InternalRound(state, k) + for k in range(4): + state = ExternalRound(state, k+4) + return state + +def Compression(inp): + return Permutation([inp[0],inp[1],F(0)]) + +def PoseidonSponge(data, capacity, output_len): + rate = 3 - capacity; + output = [F(0) for i in range(output_len)] + assert( capacity > 0 ) + assert( rate > 0 ) + assert( capacity < 3 ) + assert( rate < 3 ) + + # round up to rate the input + 1 field element ("10*" padding) + nblocks = ((len(data) + 1) + (rate-1)) // rate; + nout = (output_len + (rate-1)) // rate; + padded_len = nblocks * rate; + + padded = [] + for i in range(len(data)): + padded.append(F(data[i])) + padded.append(F(1)) + for i in range(len(data)+1,padded_len): + padded.append(F(0)) + + civ = F(0) + + state = [F(0),F(0),F(civ)] + sorbed = [F(0) for j in range(rate)] + + for m in range(nblocks): + for i in range(rate): + a = state[i] + b = padded[m*rate+i] + sorbed[i] = a + b + state = Permutation(sorbed[0:rate] + state[rate:3]) + + q = min(rate, output_len) + for i in range(q): + output[i] = state[i] + out_ptr = rate + + for n in range(1,nout): + state[nblocks+n] = Permutation(state[nblocks+n-1]) + q = min(rate, output_len-out_ptr) + for i in range(q): + output[out_ptr+i] = state[nblocks+n][i] + out_ptr += rate + + return output + + +if len(sys.argv) != Integer(4): + print("Usage: