mirror of
https://github.com/logos-blockchain/logos-blockchain-circuits.git
synced 2026-06-10 10:39:51 +00:00
176 lines
6.4 KiB
Markdown
176 lines
6.4 KiB
Markdown
# Contributor's Guide
|
|
|
|
## Development Setup
|
|
|
|
### Prerequisites
|
|
|
|
#### Sys development
|
|
|
|
- [Rust](https://rustup.rs/) — the pinned toolchain version is in `rust-toolchain.toml` and will be installed
|
|
automatically by `rustup`.
|
|
- Compiled circuit libraries (`.a` files and `witness_generator.dat`) — see [rust/README.md](rust/README.md) for how to
|
|
provide them.
|
|
|
|
#### Building circuits
|
|
|
|
- `llvm-objcopy` — required for symbol isolation when building circuit static libraries. On macOS, install via `brew
|
|
install llvm` (LLVM 20+ required).
|
|
|
|
### Pre-Commit
|
|
|
|
[pre-commit](https://pre-commit.com/) covers most of the lints required by CI. It's not mandatory — you can run checks
|
|
however you like — but it's the easiest way to catch issues before pushing.
|
|
|
|
#### Installation
|
|
|
|
```bash
|
|
pre-commit install
|
|
```
|
|
|
|
After this, they will be run automatically on every commit.
|
|
|
|
#### Running Manually
|
|
|
|
To run the checks manually against all files:
|
|
|
|
```bash
|
|
pre-commit run --all-files
|
|
```
|
|
|
|
### Maintenance
|
|
|
|
#### Rust Toolchain
|
|
|
|
When bumping the stable toolchain, update `channel` in `rust-toolchain.toml`.
|
|
The comment there lists every other place that must be updated in sync (nightly version, CI workflows, pre-commit hooks).
|
|
|
|
#### Tool Versions
|
|
|
|
`taplo`, `cargo-deny`, and `cargo-machete` are pinned in two places that must stay in sync:
|
|
|
|
- `.pre-commit-config.yaml` (hook `rev`)
|
|
- `.github/workflows/lint.yml` (`cargo install --version`)
|
|
|
|
---
|
|
|
|
## Building
|
|
|
|
For a full walkthrough of the CI build steps, from `.circom` source to release artifacts, see
|
|
[docs/build-pipeline.md](docs/build-pipeline.md).
|
|
|
|
### Symbol Isolation in Circuit Libraries
|
|
|
|
#### The Problem
|
|
|
|
Each circuit (PoQ, PoL, PoC, Signature) is compiled into a static archive (`libpoq.a`, `libpol.a`, etc.).
|
|
All archives share the same symbols, compiled from the same source files but with **different
|
|
constant values per circuit** (e.g. `get_size_of_witness()` returns 18149 for PoQ and 20531 for PoL).
|
|
When two or more circuit libraries are linked into the same binary, the linker silently picks the first definition it
|
|
encounters for each symbol and discards the rest without any sort of error or warning.
|
|
The result is that one circuit's constants end up hardwired into functions shared by both circuits, corrupting witness
|
|
parsing.
|
|
In practice: the wrong `get_size_of_witness()` value causes `loadCircuit` to compute an incorrect buffer size, `pu32`
|
|
walks off the end of the buffer, reads garbage as a length field, and the subsequent `memcpy` reads past the stack guard
|
|
page, which results in a **SIGSEGV**.
|
|
|
|
#### The Fix
|
|
|
|
The Makefile uses a two-step process to hide all circuit-specific symbols before archiving:
|
|
|
|
1. **Partial link** (`ld -r`): merges all circuit-specific `.o` files into a single relocatable
|
|
object. `fr.o` is excluded — it contains only field arithmetic with no circuit-specific calls
|
|
and is safe to deduplicate across circuits.
|
|
2. **Symbol localization**: demotes every global symbol to local except the two public FFI entry
|
|
points (`$(PROJECT)_generate_witness` and `$(PROJECT)_generate_witness_from_files`). Local
|
|
symbols are invisible to the final linker, so each archive retains a private copy.
|
|
|
|
**`llvm-objcopy` vs GNU `objcopy`**
|
|
|
|
`llvm-objcopy` is required on Linux. GNU `objcopy` only changes the binding of COMDAT signature
|
|
symbols to local, confusing the linker's deduplication logic and causing "relocation refers to
|
|
symbol in discarded section" errors. `llvm-objcopy` additionally clears the `GRP_COMDAT` flag,
|
|
turning affected sections into regular non-COMDAT sections. Slightly larger binary, no linker errors.
|
|
|
|
##### macOS
|
|
|
|
Uses `llvm-objcopy` (from `brew install llvm`, LLVM 20+).
|
|
|
|
Mach-O prepends `_` to every C symbol, so `--keep-global-symbol` arguments must include the
|
|
leading `_`. The Makefile's `SYM_PREFIX` variable handles this automatically.
|
|
|
|
##### Windows
|
|
|
|
Uses GNU's `objcopy` (from MinGW binutils).
|
|
|
|
GNU's `objcopy` works correctly on COFF, mapping local binding to storage class `C_STAT`.
|
|
The ELF `GRP_COMDAT` problem doesn't apply: COFF COMDAT is per-section rather than group-based.
|
|
|
|
#### FFI Maintenance
|
|
|
|
`PUBLIC_SYMS` is hardcoded to `$(PROJECT)_generate_witness` and `$(PROJECT)_generate_witness_from_files` in the
|
|
Makefile. If the public FFI API ever changes — entry points renamed or new ones added — update that variable, otherwise
|
|
the affected symbols will be localized and linking will fail.
|
|
|
|
---
|
|
|
|
## Releasing
|
|
|
|
### Triggering a Release Build
|
|
|
|
To trigger a release build:
|
|
|
|
1. Create and push a tag in the format `vX.Y.Z`:
|
|
|
|
```bash
|
|
git tag v1.2.3 -m "Release v1.2.3"
|
|
git push --tags
|
|
```
|
|
|
|
2. This will automatically trigger the `.github/workflows/build_circuits.yml` workflow.
|
|
3. Once the workflow finishes, the generated artifacts will be attached to a new release.
|
|
|
|
> Pull Requests will also generate artifacts, which may be found on the job's page, but won't generate a new release.
|
|
|
|
#### Generated artifacts
|
|
|
|
For each supported platform (Linux x86_64, Linux aarch64, macOS aarch64, Windows x86_64), a release artifact is
|
|
generated:
|
|
|
|
**`logos-blockchain-circuits-{version}-{os}-{arch}.tar.gz`** — a complete bundle containing all components needed to
|
|
generate and verify proofs for all circuits.
|
|
|
|
**Bundle Structure:**
|
|
|
|
```text
|
|
logos-blockchain-circuits-{version}-{os}-{arch}/
|
|
├── lib/
|
|
│ └── libgmp.a
|
|
├── {circuit}/ (poc/, pol/, poq/, signature/)
|
|
│ ├── include/
|
|
│ ├── lib{circuit}.a
|
|
│ ├── proving_key.zkey
|
|
│ ├── verification_key.json
|
|
│ └── witness_generator.dat
|
|
├── prover[.exe]
|
|
├── verifier[.exe]
|
|
└── VERSION
|
|
```
|
|
|
|
> On Windows, static libraries use the `.lib` extension instead of `.a` (e.g. `pol.lib`, `gmp.lib`).
|
|
|
|
The proving keys are generated using the Hermez Powers of Tau ceremony — see [docs/build-pipeline.md § Step 2](docs/build-pipeline.md#step-2--proving-key-generation).
|
|
|
|
### Publishing
|
|
|
|
Releases are marked as **Draft** and **Pre-Release** to ensure the changelog and pre-release steps are manually reviewed
|
|
before going public. Before publishing:
|
|
|
|
1. **Review the changelog**
|
|
Ensure that all relevant changes are clearly listed and properly formatted.
|
|
|
|
2. **Confirm the pre-release checklist**
|
|
Verify that all required steps have been completed, then remove the checklist from the release notes.
|
|
3. **Mark the release as published**
|
|
- Uncheck **“This is a pre-release.”**
|
|
- Publish the release (removing the Draft state).
|