Compare commits

..

17 Commits
v0.3.1 ... main

Author SHA1 Message Date
Álex
480b9bc4fd
Merge pull request #11 from logos-blockchain/feat/nixify
feat: Nixify
2026-01-30 14:33:49 +01:00
Alejandro Cabeza Romero
1576b3a31f
Set default version and add todo. 2026-01-28 16:54:20 +01:00
Alejandro Cabeza Romero
df057aa15a
wip 2026-01-28 16:51:29 +01:00
Alejandro Cabeza Romero
b71a648643
Add separate versions file. 2026-01-28 16:38:11 +01:00
Alejandro Cabeza Romero
d8992faa1d
Format flake. 2026-01-28 16:26:46 +01:00
Alejandro Cabeza Romero
e32eb38519
Nixify circuits. 2026-01-28 16:24:43 +01:00
davidrusu
6f16952675
Merge pull request #10 from logos-blockchain/rpi5-releases
Linux_aarch64 builds for RPI
2026-01-22 01:18:56 +04:00
David Rusu
b79e0ff754 rename arm64 to aarch64 2026-01-21 15:45:54 +04:00
David Rusu
7ebee1bf89 use arm64 runner to generate native builds 2026-01-21 14:30:15 +04:00
David Rusu
df27d2781a another attempt at GMP fixes 2026-01-21 13:56:55 +04:00
David Rusu
b5caecaadc fix GMP compilation problems for RPI 2026-01-21 13:41:02 +04:00
David Rusu
3973af3e63 add linux_aarch64 builds for RPI 2026-01-21 13:11:32 +04:00
Antonio
678ea4e75e
Merge pull request #9 from logos-blockchain/aa/change-circuits-output
chore: rename nomos to logos-blockchain
2026-01-20 11:12:23 +01:00
Antonio Antonino
0b9ad0bdb6
Rename nomos to logos-blockchain 2026-01-19 14:54:26 +01:00
thomaslavaur
0b0054a57b
Merge pull request #7 from logos-blockchain/tl/PoL_update
Tl/po l update
2026-01-15 13:15:36 +01:00
thomaslavaur
e84e7f801c fix misspelling 2026-01-15 12:42:36 +01:00
thomaslavaur
6aa15f2bd7 remove protection against adaptive adversaries and update DSTs 2026-01-15 12:39:41 +01:00
16 changed files with 462 additions and 147 deletions

View File

@ -23,6 +23,17 @@ host_linux_x86_64_static:
-DCMAKE_PREFIX_PATH=depends/gmp/package && \ -DCMAKE_PREFIX_PATH=depends/gmp/package && \
make -j$(nproc) -vvv && make install make -j$(nproc) -vvv && make install
host_linux_aarch64_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
host_windows_x86_64_static: host_windows_x86_64_static:
rm -rf build_prover && mkdir build_prover && cd build_prover && \ rm -rf build_prover && mkdir build_prover && cd build_prover && \
cmake .. \ cmake .. \

View File

@ -13,7 +13,7 @@ OBJS := $(SRCS:.cpp=.o)
DEPS_HPP := circom.hpp calcwit.hpp fr.hpp DEPS_HPP := circom.hpp calcwit.hpp fr.hpp
BIN := $(PROJECT) BIN := $(PROJECT)
# ---- Linux ---- # ---- Linux (x86_64 and aarch64) ----
linux: CXXFLAGS=$(CXXFLAGS_COMMON) linux: CXXFLAGS=$(CXXFLAGS_COMMON)
linux: LDFLAGS=-static linux: LDFLAGS=-static
linux: LDLIBS=-lgmp linux: LDLIBS=-lgmp

View File

@ -326,7 +326,7 @@ jobs:
- name: Create Unified Release Bundle - name: Create Unified Release Bundle
env: env:
BUNDLE_NAME: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }} BUNDLE_NAME: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}
run: | run: |
# Create the bundle directory structure # Create the bundle directory structure
mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc} mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc}
@ -374,8 +374,248 @@ jobs:
- name: Upload Unified Release Bundle - name: Upload Unified Release Bundle
uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8
with: with:
name: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz name: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
path: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz path: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
build-linux-aarch64:
name: Build Linux aarch64 Binaries (Native for RPI5)
runs-on: ubuntu-22.04-arm
needs:
- setup
- generate-proving-keys
env:
VERSION: ${{ needs.setup.outputs.version }}
OS: linux
ARCH: aarch64
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: 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 -y nlohmann-json3-dev
- name: Replace Prover Makefile
run: cp .github/resources/prover/Makefile rapidsnark/Makefile
- name: Cache GMP Archive
id: cache-gmp
uses: actions/cache@v4
with:
path: rapidsnark/depends/gmp-6.2.1.tar.xz
key: gmp-6.2.1
- name: Download GMP Archive
if: steps.cache-gmp.outputs.cache-hit != 'true'
working-directory: rapidsnark/depends
run: |
echo "Downloading GMP archive..."
curl -L -o gmp-6.2.1.tar.xz https://ftpmirror.gnu.org/gmp/gmp-6.2.1.tar.xz
echo "Download complete."
- name: Compile Prover and Verifier
working-directory: rapidsnark
run: |
./build_gmp.sh host
# Create symlink for TARGET_PLATFORM=aarch64 to find GMP
ln -s package depends/gmp/package_aarch64
make host_linux_aarch64_static
- name: Bundle Rapidsnark Prover
env:
BINARY_NAME: prover
BUNDLE_NAME: prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}
RAPIDSNARK_DIR: 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: 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 PoL Witness Generator
uses: ./.github/actions/compile-witness-generator
with:
circuit-name-display: "PoL"
circuit-name-binary: "pol"
circuit-path: "mantle/pol.circom"
version: ${{ env.VERSION }}
os: ${{ env.OS }}
arch: ${{ env.ARCH }}
- name: Compile PoQ Witness Generator
uses: ./.github/actions/compile-witness-generator
with:
circuit-name-display: "PoQ"
circuit-name-binary: "poq"
circuit-path: "blend/poq.circom"
version: ${{ env.VERSION }}
os: ${{ env.OS }}
arch: ${{ env.ARCH }}
- name: Compile ZKSign Witness Generator
uses: ./.github/actions/compile-witness-generator
with:
circuit-name-display: "ZKSign"
circuit-name-binary: "zksign"
circuit-path: "mantle/signature.circom"
version: ${{ env.VERSION }}
os: ${{ env.OS }}
arch: ${{ env.ARCH }}
- name: Compile PoC Witness Generator
uses: ./.github/actions/compile-witness-generator
with:
circuit-name-display: "PoC"
circuit-name-binary: "poc"
circuit-path: "mantle/poc.circom"
version: ${{ env.VERSION }}
os: ${{ env.OS }}
arch: ${{ env.ARCH }}
- name: Download PoL Witness Generator
uses: actions/download-artifact@448e3f862ab3ef47aa50ff917776823c9946035b
with:
name: pol-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}
path: witness-generators/pol-artifact
- name: Download PoQ Witness Generator
uses: actions/download-artifact@448e3f862ab3ef47aa50ff917776823c9946035b
with:
name: poq-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}
path: witness-generators/poq-artifact
- name: Download ZKSign Witness Generator
uses: actions/download-artifact@448e3f862ab3ef47aa50ff917776823c9946035b
with:
name: zksign-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}
path: witness-generators/zksign-artifact
- name: Download PoC Witness Generator
uses: actions/download-artifact@448e3f862ab3ef47aa50ff917776823c9946035b
with:
name: poc-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}
path: witness-generators/poc-artifact
- name: Download All Proving Key Artifacts
uses: actions/download-artifact@448e3f862ab3ef47aa50ff917776823c9946035b
with:
pattern: "*-proving-key"
path: proving-keys/
- name: Download Prover Artifact
uses: actions/download-artifact@448e3f862ab3ef47aa50ff917776823c9946035b
with:
name: prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
path: prover-artifact/
- name: Download Verifier Artifact
uses: actions/download-artifact@448e3f862ab3ef47aa50ff917776823c9946035b
with:
name: verifier-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
path: verifier-artifact/
- name: Create Unified Release Bundle
env:
BUNDLE_NAME: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}
run: |
# Create the bundle directory structure
mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc}
# Create VERSION file
echo "${{ env.VERSION }}" > "${BUNDLE_NAME}/VERSION"
# Extract and add prover and verifier binaries
tar -xzf prover-artifact/prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz -C .
tar -xzf verifier-artifact/verifier-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz -C .
mv prover-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}/prover/prover "${BUNDLE_NAME}/prover"
mv verifier-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}/verifier/verifier "${BUNDLE_NAME}/verifier"
chmod +x "${BUNDLE_NAME}/prover"
chmod +x "${BUNDLE_NAME}/verifier"
# Move witness generators into their respective circuit directories
mv witness-generators/pol-artifact/pol "${BUNDLE_NAME}/pol/witness_generator"
mv witness-generators/pol-artifact/pol.dat "${BUNDLE_NAME}/pol/witness_generator.dat"
mv witness-generators/poq-artifact/poq "${BUNDLE_NAME}/poq/witness_generator"
mv witness-generators/poq-artifact/poq.dat "${BUNDLE_NAME}/poq/witness_generator.dat"
mv witness-generators/zksign-artifact/signature "${BUNDLE_NAME}/zksign/witness_generator"
mv witness-generators/zksign-artifact/signature.dat "${BUNDLE_NAME}/zksign/witness_generator.dat"
mv witness-generators/poc-artifact/poc "${BUNDLE_NAME}/poc/witness_generator"
mv witness-generators/poc-artifact/poc.dat "${BUNDLE_NAME}/poc/witness_generator.dat"
# Restore execute permissions on witness generators
chmod +x "${BUNDLE_NAME}/pol/witness_generator"
chmod +x "${BUNDLE_NAME}/poq/witness_generator"
chmod +x "${BUNDLE_NAME}/zksign/witness_generator"
chmod +x "${BUNDLE_NAME}/poc/witness_generator"
# Copy proving keys and verification keys into each circuit directory
cp proving-keys/pol-proving-key/pol.zkey "${BUNDLE_NAME}/pol/proving_key.zkey"
cp proving-keys/pol-proving-key/pol_verification_key.json "${BUNDLE_NAME}/pol/verification_key.json"
cp proving-keys/poq-proving-key/poq.zkey "${BUNDLE_NAME}/poq/proving_key.zkey"
cp proving-keys/poq-proving-key/poq_verification_key.json "${BUNDLE_NAME}/poq/verification_key.json"
cp proving-keys/zksign-proving-key/zksign.zkey "${BUNDLE_NAME}/zksign/proving_key.zkey"
cp proving-keys/zksign-proving-key/zksign_verification_key.json "${BUNDLE_NAME}/zksign/verification_key.json"
cp proving-keys/poc-proving-key/poc.zkey "${BUNDLE_NAME}/poc/proving_key.zkey"
cp proving-keys/poc-proving-key/poc_verification_key.json "${BUNDLE_NAME}/poc/verification_key.json"
# Create tarball
tar -czf "${BUNDLE_NAME}.tar.gz" "${BUNDLE_NAME}"
- name: Upload Unified Release Bundle
uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8
with:
name: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
path: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
build-windows: build-windows:
name: Build Windows Binaries (Native) name: Build Windows Binaries (Native)
@ -605,7 +845,7 @@ jobs:
- name: Create Unified Release Bundle - name: Create Unified Release Bundle
shell: msys2 {0} shell: msys2 {0}
env: env:
BUNDLE_NAME: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }} BUNDLE_NAME: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}
run: | run: |
# Create the bundle directory structure # Create the bundle directory structure
mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc} mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc}
@ -645,8 +885,8 @@ jobs:
- name: Upload Unified Release Bundle - name: Upload Unified Release Bundle
uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8
with: with:
name: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz name: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
path: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz path: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
build-macos: build-macos:
name: Build MacOS Binaries (Native) name: Build MacOS Binaries (Native)
@ -831,7 +1071,7 @@ jobs:
- name: Create Unified Release Bundle - name: Create Unified Release Bundle
env: env:
BUNDLE_NAME: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }} BUNDLE_NAME: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}
run: | run: |
# Create the bundle directory structure # Create the bundle directory structure
mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc} mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc}
@ -879,8 +1119,8 @@ jobs:
- name: Upload Unified Release Bundle - name: Upload Unified Release Bundle
uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8
with: with:
name: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz name: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
path: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz path: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
publish-release: publish-release:
name: Create Release name: Create Release
@ -891,6 +1131,7 @@ jobs:
- setup - setup
- generate-proving-keys - generate-proving-keys
- build-linux - build-linux
- build-linux-aarch64
- build-windows - build-windows
- build-macos - build-macos
env: env:
@ -937,13 +1178,15 @@ jobs:
platform: platform:
- os: linux - os: linux
arch: x86_64 arch: x86_64
- os: linux
arch: aarch64
- os: macos - os: macos
arch: aarch64 arch: aarch64
- os: windows - os: windows
arch: x86_64 arch: x86_64
env: env:
UPLOAD_URL: ${{ needs.publish-release.outputs.upload_url }} UPLOAD_URL: ${{ needs.publish-release.outputs.upload_url }}
ARTIFACT_NAME: nomos-circuits-${{ needs.setup.outputs.version }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}.tar.gz ARTIFACT_NAME: logos-blockchain-circuits-${{ needs.setup.outputs.version }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}.tar.gz
steps: steps:
- name: Download Unified Bundle - name: Download Unified Bundle
uses: actions/download-artifact@448e3f862ab3ef47aa50ff917776823c9946035b uses: actions/download-artifact@448e3f862ab3ef47aa50ff917776823c9946035b

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea/
result

View File

@ -1,6 +1,6 @@
# Contributor's Guide # Contributor's Guide
## Triggering a New Release for Nomos Circuits ## Triggering a New Release for Logos Blockchain Circuits
To trigger a release build: To trigger a release build:
@ -18,14 +18,14 @@ Each release includes a single unified bundle per platform:
For each supported platform (Linux x86_64, macOS aarch64, Windows x86_64): For each supported platform (Linux x86_64, macOS aarch64, Windows x86_64):
- **`nomos-circuits-{version}-{os}-{arch}.tar.gz`** - **`logos-blockchain-circuits-{version}-{os}-{arch}.tar.gz`**
A complete bundle containing all components needed to generate and verify proofs for all circuits. A complete bundle containing all components needed to generate and verify proofs for all circuits.
**Bundle Structure:** **Bundle Structure:**
``` ```
nomos-circuits-{version}-{os}-{arch}/ logos-blockchain-circuits-{version}-{os}-{arch}/
├── VERSION ├── VERSION
├── prover[.exe] ├── prover[.exe]
├── verifier[.exe] ├── verifier[.exe]
@ -87,5 +87,5 @@ Once everything looks good:
- Uncheck **“This is a pre-release.”** - Uncheck **“This is a pre-release.”**
- Publish the release (removing the Draft state). - Publish the release (removing the Draft state).
> ⚡ **Important:** Nomos builds will only pick up the new circuits once the release is published as **Latest** (i.e. not marked as draft or pre-release). > ⚡ **Important:** Logos Blockchain builds will only pick up the new circuits once the release is published as **Latest** (i.e. not marked as draft or pre-release).

View File

@ -1 +1 @@
# Nomos Circuits # Logos Blockchain Circuits

View File

@ -221,7 +221,7 @@ if not core_or_leader in [0,1]:
# 1) Corenode registry Merkleproof # 1) Corenode registry Merkleproof
# pick a random core_sk and derive its public key # pick a random core_sk and derive its public key
core_sk = F(randrange(0,p,1)) core_sk = F(randrange(0,p,1))
pk_core = Compression([ F(1296193216988918402894), core_sk ]) pk_core = Compression([ F(4605003), core_sk ])
core_selectors = randrange(0,2**20,1) core_selectors = randrange(0,2**20,1)
core_selectors = format(int(core_selectors),'020b') core_selectors = format(int(core_selectors),'020b')
core_nodes = [F(randrange(0,p,1)) for i in range(20)] core_nodes = [F(randrange(0,p,1)) for i in range(20)]
@ -247,30 +247,18 @@ t1 = F(p- (int(t1_constant) // total_stake**2))
value = F(total_stake / 100) value = F(total_stake / 100)
threshold = (t0 + t1 * value) * value 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')
sk = F(randrange(0,p,1))
tx_hash = F(randrange(0,p,1)) tx_hash = F(randrange(0,p,1))
output_number = F(randrange(0,50,1)) output_number = F(randrange(0,50,1))
pk = Compression([F(4605003),sk])
slot_secret_path = [F(randrange(0,p,1)) for i in range(25)] note_id = poseidon2_hash([F(232989242343357190262606),tx_hash,output_number,value,pk])
secret_root = slot_secret
for i in range(25):
if int(slot_secret_indexes[24-i]) == 0:
secret_root = Compression([secret_root,slot_secret_path[i]])
else:
secret_root = Compression([slot_secret_path[i],secret_root])
sk = poseidon2_hash([F(256174383281726064679014503048630094),starting_slot,secret_root])
pk = Compression([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]) ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk])
while(ticket > threshold): while(ticket > threshold):
output_number += 1 output_number += 1
note_id = poseidon2_hash([F(65580641562429851895355409762135920462),tx_hash,output_number,value,pk]) note_id = poseidon2_hash([F(232989242343357190262606),tx_hash,output_number,value,pk])
ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk]) 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_nodes = [F(randrange(0,p,1)) for i in range(32)]
@ -308,13 +296,11 @@ inp = {
"pol_epoch_nonce": str(epoch_nonce), "pol_epoch_nonce": str(epoch_nonce),
"pol_t0": str(t0), "pol_t0": str(t0),
"pol_t1": str(t1), "pol_t1": str(t1),
"pol_slot_secret": str(slot_secret), "pol_secret_key": str(sk),
"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": [str(x) for x in aged_nodes],
"pol_noteid_path_selectors": [str(x) for x in aged_selectors], "pol_noteid_path_selectors": [str(x) for x in aged_selectors],
"pol_note_tx_hash": str(tx_hash), "pol_note_tx_hash": str(tx_hash),
"pol_note_output_number": str(output_number), "pol_note_output_number": str(output_number),
"pol_sk_starting_slot": str(starting_slot),
"pol_note_value": str(value) "pol_note_value": str(value)
} }

View File

@ -2,7 +2,7 @@
pragma circom 2.1.9; pragma circom 2.1.9;
include "../hash_bn/poseidon2_hash.circom"; include "../hash_bn/poseidon2_hash.circom";
include "../misc/constants.circom"; // defines NOMOS_KDF, SELECTION_RANDOMNESS, PROOF_NULLIFIER include "../misc/constants.circom"; // defines KDF, SELECTION_RANDOMNESS, PROOF_NULLIFIER
include "../misc/comparator.circom"; include "../misc/comparator.circom";
include "../circomlib/circuits/bitify.circom"; include "../circomlib/circuits/bitify.circom";
include "../mantle/pol_lib.circom"; // defines proof_of_leadership include "../mantle/pol_lib.circom"; // defines proof_of_leadership
@ -48,15 +48,13 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
signal input pol_epoch_nonce; signal input pol_epoch_nonce;
signal input pol_t0; signal input pol_t0;
signal input pol_t1; 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[32];
signal input pol_noteid_path_selectors[32]; signal input pol_noteid_path_selectors[32];
signal input pol_secret_key;
signal input pol_note_tx_hash; signal input pol_note_tx_hash;
signal input pol_note_output_number; signal input pol_note_output_number;
signal input pol_sk_starting_slot;
signal input pol_note_value; signal input pol_note_value;
@ -96,10 +94,6 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
would_win.epoch_nonce <== pol_epoch_nonce; would_win.epoch_nonce <== pol_epoch_nonce;
would_win.t0 <== pol_t0; would_win.t0 <== pol_t0;
would_win.t1 <== pol_t1; 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++) { for (var i = 0; i < 32; i++) {
would_win.aged_nodes[i] <== pol_noteid_path[i]; would_win.aged_nodes[i] <== pol_noteid_path[i];
would_win.aged_selectors[i] <== pol_noteid_path_selectors[i]; would_win.aged_selectors[i] <== pol_noteid_path_selectors[i];
@ -107,7 +101,7 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
would_win.aged_root <== pol_ledger_aged; would_win.aged_root <== pol_ledger_aged;
would_win.transaction_hash <== pol_note_tx_hash; would_win.transaction_hash <== pol_note_tx_hash;
would_win.output_number <== pol_note_output_number; would_win.output_number <== pol_note_output_number;
would_win.starting_slot <== pol_sk_starting_slot; would_win.secret_key <== pol_secret_key;
would_win.value <== pol_note_value; would_win.value <== pol_note_value;
// Enforce the selected role is correct // Enforce the selected role is correct

27
flake.lock generated Normal file
View File

@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1769461804,
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

95
flake.nix Normal file
View File

@ -0,0 +1,95 @@
{
description = "Logos Blockchain Circuits (GitHub Releases)";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs =
{ nixpkgs, ... }:
let
lib = nixpkgs.lib;
systems = [
"x86_64-linux"
"aarch64-linux"
"aarch64-darwin"
"x86_64-windows"
];
forAll = lib.genAttrs systems;
circuitsVersion = "0.3.2"; # TODO: Parametrize or make package per version available
versions = import ./versions.nix;
circuitsHashes = versions.${circuitsVersion};
githubBase = "https://github.com/logos-blockchain/logos-blockchain-circuits/releases/download";
mkCircuits =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
os =
if pkgs.stdenv.isLinux then
"linux"
else if pkgs.stdenv.isDarwin then
"macos"
else if pkgs.stdenv.isWindows then
"windows"
else
throw "Unsupported OS";
arch =
if pkgs.stdenv.isx86_64 then
"x86_64"
else if pkgs.stdenv.isAarch64 then
"aarch64"
else
throw "Unsupported architecture.";
sha256 =
if circuitsHashes ? ${system} then
circuitsHashes.${system}
else
throw "logos-blockchain-circuits ${circuitsVersion} does not support ${system}.";
in
pkgs.stdenv.mkDerivation {
pname = "logos-blockchain-circuits";
version = circuitsVersion;
phases = [ "installPhase" ];
src = pkgs.fetchurl {
url =
"${githubBase}/v${circuitsVersion}"
+ "/logos-blockchain-circuits-v${circuitsVersion}-${os}-${arch}.tar.gz";
inherit sha256;
};
installPhase = ''
mkdir -p $out
tar -xzf $src -C $out --strip-components=1
'';
meta = {
platforms = [ system ];
};
passthru = {
version = circuitsVersion;
};
};
in
{
packages = forAll (
system:
let
circuits = mkCircuits system;
in
{
inherit circuits;
default = circuits;
}
);
};
}

View File

@ -5,26 +5,12 @@ include "../hash_bn/poseidon2_hash.circom";
include "../hash_bn/poseidon2_perm.circom"; include "../hash_bn/poseidon2_perm.circom";
include "../misc/constants.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(){ template derive_public_key(){
signal input secret_key; signal input secret_key;
signal output out; signal output out;
component hash = Compression(); component hash = Compression();
component dst = NOMOS_KDF(); component dst = KDF();
hash.inp[0] <== dst.out; hash.inp[0] <== dst.out;
hash.inp[1] <== secret_key; hash.inp[1] <== secret_key;
out <== hash.out; out <== hash.out;

View File

@ -228,30 +228,17 @@ t1 = F(p- (int(t1_constant) // total_stake**2))
value = F(total_stake / 100) value = F(total_stake / 100)
threshold = (t0 + t1 * value) * value 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')
sk = F(randrange(0,p,1))
tx_hash = F(randrange(0,p,1)) tx_hash = F(randrange(0,p,1))
output_number = F(randrange(0,50,1)) output_number = F(randrange(0,50,1))
pk = Compression([F(4605003),sk])
note_id = poseidon2_hash([F(232989242343357190262606),tx_hash,output_number,value,pk])
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 = Compression([secret_root,slot_secret_path[i]])
else:
secret_root = Compression([slot_secret_path[i],secret_root])
sk = poseidon2_hash([F(256174383281726064679014503048630094),starting_slot,secret_root])
pk = Compression([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]) ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk])
while(ticket > threshold): while(ticket > threshold):
output_number += 1 output_number += 1
note_id = poseidon2_hash([F(65580641562429851895355409762135920462),tx_hash,output_number,value,pk]) note_id = poseidon2_hash([F(232989242343357190262606),tx_hash,output_number,value,pk])
ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk]) 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_nodes = [F(randrange(0,p,1)) for i in range(32)]
@ -284,10 +271,9 @@ inp = {
"epoch_nonce": str(epoch_nonce), "epoch_nonce": str(epoch_nonce),
"t0": str(t0), "t0": str(t0),
"t1": str(t1), "t1": str(t1),
"slot_secret": str(slot_secret), "secret_key": str(sk),
"P_lead_part_one": str(F(123456)), "P_lead_part_one": str(F(123456)),
"P_lead_part_two": str(F(654321)), "P_lead_part_two": str(F(654321)),
"slot_secret_path": [str(x) for x in slot_secret_path],
"noteid_aged_path": [str(x) for x in aged_nodes], "noteid_aged_path": [str(x) for x in aged_nodes],
"noteid_aged_selectors": [str(x) for x in aged_selectors], "noteid_aged_selectors": [str(x) for x in aged_selectors],
"ledger_aged": str(aged_root), "ledger_aged": str(aged_root),
@ -296,7 +282,6 @@ inp = {
"noteid_latest_path": [str(x) for x in unspent_nodes], "noteid_latest_path": [str(x) for x in unspent_nodes],
"noteid_latest_selectors": [str(x) for x in unspent_selectors], "noteid_latest_selectors": [str(x) for x in unspent_selectors],
"ledger_latest": str(latest_root), "ledger_latest": str(latest_root),
"starting_slot": str(starting_slot),
"v": str(value) "v": str(value)
} }

View File

@ -34,7 +34,7 @@ template derive_entropy(){
signal output out; signal output out;
component hash = Poseidon2_hash(4); component hash = Poseidon2_hash(4);
component dst = NOMOS_NONCE_CONTRIB_V1(); component dst = NONCE_CONTRIB_V1();
hash.inp[0] <== dst.out; hash.inp[0] <== dst.out;
hash.inp[1] <== slot; hash.inp[1] <== slot;
hash.inp[2] <== note_id; hash.inp[2] <== note_id;
@ -48,8 +48,6 @@ template would_win_leadership(secret_depth){
signal input epoch_nonce; signal input epoch_nonce;
signal input t0; signal input t0;
signal input t1; signal input t1;
signal input slot_secret;
signal input slot_secret_path[secret_depth];
//Part of the note id proof of membership to prove aged //Part of the note id proof of membership to prove aged
signal input aged_nodes[32]; signal input aged_nodes[32];
@ -59,51 +57,23 @@ template would_win_leadership(secret_depth){
//Used to derive the note identifier //Used to derive the note identifier
signal input transaction_hash; signal input transaction_hash;
signal input output_number; signal input output_number;
signal input secret_key;
//Part of the secret key
signal input starting_slot;
// The winning note value // The winning note value
signal input value; signal input value;
signal output out; signal output out;
signal output note_identifier; signal output note_identifier;
signal output secret_key;
// Derivation of the secrets root from the slot secret at position slot - starting_slot
// Verify that the substraction wont underflow (starting_slot < slot)
component checker = SafeFullLessThan();
checker.a <== starting_slot;
checker.b <== slot;
// Compute the positions related to slot - starting_slot and make sure slot - starting_slot is a 25 bits number
component bits = Num2Bits(secret_depth);
bits.in <== slot - starting_slot;
// Derive the secrets root
component secrets_root = compute_merkle_root(secret_depth);
for(var i=0; i<secret_depth; i++){
secrets_root.nodes[i] <== slot_secret_path[i];
secrets_root.selector[i] <== bits.out[secret_depth-1-i];
}
secrets_root.leaf <== slot_secret;
// Derive the secret key
component sk = derive_secret_key();
sk.starting_slot <== starting_slot;
sk.secrets_root <== secrets_root.root;
// Derive the public key from the secret key // Derive the public key from the secret key
component pk = derive_public_key(); component pk = derive_public_key();
pk.secret_key <== sk.out; pk.secret_key <== secret_key;
// Derive the note id // Derive the note id
component note_id = Poseidon2_hash(5); component note_id = Poseidon2_hash(5);
component dst_note_id = NOMOS_NOTE_ID_V1(); component dst_note_id = NOTE_ID_V1();
note_id.inp[0] <== dst_note_id.out; note_id.inp[0] <== dst_note_id.out;
note_id.inp[1] <== transaction_hash; note_id.inp[1] <== transaction_hash;
note_id.inp[2] <== output_number; note_id.inp[2] <== output_number;
@ -131,7 +101,7 @@ template would_win_leadership(secret_depth){
ticket.epoch_nonce <== epoch_nonce; ticket.epoch_nonce <== epoch_nonce;
ticket.slot <== slot; ticket.slot <== slot;
ticket.note_id <== note_id.out; ticket.note_id <== note_id.out;
ticket.secret_key <== sk.out; ticket.secret_key <== secret_key;
// Compute the lottery threshold // Compute the lottery threshold
@ -147,12 +117,9 @@ template would_win_leadership(secret_depth){
winning.b <== threshold; winning.b <== threshold;
// Check that every constraint holds // Check that every constraint holds
signal intermediate_out; out <== aged_membership.out * winning.out;
intermediate_out <== aged_membership.out * winning.out;
out <== intermediate_out * checker.out;
note_identifier <== note_id.out; note_identifier <== note_id.out;
secret_key <== sk.out;
} }
@ -161,8 +128,6 @@ template proof_of_leadership(secret_depth){
signal input epoch_nonce; // the epoch nonce eta signal input epoch_nonce; // the epoch nonce eta
signal input t0; signal input t0;
signal input t1; signal input t1;
signal input slot_secret; // This is r_sl
signal input slot_secret_path[secret_depth];
//Part of the note id proof of membership to prove aged //Part of the note id proof of membership to prove aged
signal input noteid_aged_path[32]; signal input noteid_aged_path[32];
@ -170,6 +135,7 @@ template proof_of_leadership(secret_depth){
signal input ledger_aged; signal input ledger_aged;
//Used to derive the note identifier //Used to derive the note identifier
signal input secret_key;
signal input note_tx_hash; signal input note_tx_hash;
signal input note_output_number; signal input note_output_number;
@ -178,10 +144,7 @@ template proof_of_leadership(secret_depth){
signal input noteid_latest_selectors[32]; // must be bits signal input noteid_latest_selectors[32]; // must be bits
signal input ledger_latest; signal input ledger_latest;
//Part of the secret key // The winning note.
signal input starting_slot;
// The winning note. The unit is supposed to be NMO and the ZoneID is MANTLE
signal input v; // value of the note signal input v; // value of the note
@ -191,10 +154,6 @@ template proof_of_leadership(secret_depth){
lottery_checker.epoch_nonce <== epoch_nonce; lottery_checker.epoch_nonce <== epoch_nonce;
lottery_checker.t0 <== t0; lottery_checker.t0 <== t0;
lottery_checker.t1 <== t1; lottery_checker.t1 <== t1;
lottery_checker.slot_secret <== slot_secret;
for(var i = 0; i < secret_depth; i++){
lottery_checker.slot_secret_path[i] <== slot_secret_path[i];
}
for(var i = 0; i < 32; i++){ for(var i = 0; i < 32; i++){
lottery_checker.aged_nodes[i] <== noteid_aged_path[i]; lottery_checker.aged_nodes[i] <== noteid_aged_path[i];
lottery_checker.aged_selectors[i] <== noteid_aged_selectors[i]; lottery_checker.aged_selectors[i] <== noteid_aged_selectors[i];
@ -202,7 +161,7 @@ template proof_of_leadership(secret_depth){
lottery_checker.aged_root <== ledger_aged; lottery_checker.aged_root <== ledger_aged;
lottery_checker.transaction_hash <== note_tx_hash; lottery_checker.transaction_hash <== note_tx_hash;
lottery_checker.output_number <== note_output_number; lottery_checker.output_number <== note_output_number;
lottery_checker.starting_slot <== starting_slot; lottery_checker.secret_key <== secret_key;
lottery_checker.value <== v; lottery_checker.value <== v;
@ -241,7 +200,7 @@ template proof_of_leadership(secret_depth){
component entropy = derive_entropy(); component entropy = derive_entropy();
entropy.slot <== sl; entropy.slot <== sl;
entropy.note_id <== lottery_checker.note_identifier; entropy.note_id <== lottery_checker.note_identifier;
entropy.secret_key <== lottery_checker.secret_key; entropy.secret_key <== secret_key;
entropy_contribution <== entropy.out; entropy_contribution <== entropy.out;
} }

View File

@ -11,31 +11,24 @@ template LEAD_V1(){
} }
// int.from_bytes(b"NOMOS_POL_SK_V1", byteorder="little") = 256174383281726064679014503048630094 // int.from_bytes(b"NONCE_CONTRIB_V1", byteorder="little") = 65580641403957881555985426713123114830
template NOMOS_POL_SK_V1(){ template NONCE_CONTRIB_V1(){
signal output out; signal output out;
out <== 256174383281726064679014503048630094; out <== 65580641403957881555985426713123114830;
} }
// int.from_bytes(b"NOMOS_NONCE_CONTRIB_V1", byteorder="little") = 18459309511848927313552932915476467038165525790019406 // int.from_bytes(b"KDF", byteorder="little") = 4605003
template NOMOS_NONCE_CONTRIB_V1(){ template KDF(){
signal output out; signal output out;
out <== 18459309511848927313552932915476467038165525790019406; out <== 4605003;
} }
// int.from_bytes(b"NOMOS_KDF", byteorder="little") = 1296193216988918402894 // int.from_bytes(b"NOTE_ID_V1", byteorder="little") = 232989242343357190262606
template NOMOS_KDF(){ template NOTE_ID_V1(){
signal output out; signal output out;
out <== 1296193216988918402894; out <== 232989242343357190262606;
}
// int.from_bytes(b"NOMOS_NOTE_ID_V1", byteorder="little") = 65580641562429851895355409762135920462
template NOMOS_NOTE_ID_V1(){
signal output out;
out <== 65580641562429851895355409762135920462;
} }

21
scripts/gh-hash-to-nix.sh Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail
if [ $# -ne 1 ]; then
echo "usage: $0 <sha256-hex | sha256:hex | sha256-SRI>"
exit 1
fi
input="$1"
# If already SRI, print as-is
if [[ "$input" =~ ^sha256- ]]; then
echo "$input"
exit 0
fi
# Strip optional sha256: prefix
hex="${input#sha256:}"
# Convert hex → SRI
nix hash convert --hash-algo sha256 "$hex"

13
versions.nix Normal file
View File

@ -0,0 +1,13 @@
{
"0.3.2" = {
x86_64-linux = "sha256-80+GrB3kBhwLHvNemme5Vig6tPDRRZC7xHps0DNonzM=";
aarch64-darwin = "sha256-FbLgrHaa8djFEaA69WpZMB3uozkLT/abQiCWKrkzcsk=";
x86_64-windows = "sha256-VOBUXlXNHTY0l91G+B1vybDfES0Y0HXhUytJIfFEiBA=";
};
"0.4.1" = {
x86_64-linux = "sha256-Oi3xhqm5Sd4PaCSHWMvsJm2YPtSlm11BBG99xG30tiM=";
aarch64-linux = "sha256-8lsgqflHXPP6mnxILpUCNhetpVeDNOXiQlWKoZLHa7I=";
aarch64-darwin = "sha256-E+yMjJPMy08jbiHLlDmDvlKnGJ4UiIRKB9GGZ0JGBB8=";
x86_64-windows = "sha256-8qceJxNt+OGF5cRNwNG146Op5xcqbShQEtmVJ6iDvmQ=";
};
}