The pure-Zig, FFI-free cryptography that a live Solana validator runs, extracted with its byte-exactness proof carried alongside it.
zolcrypt is the cryptographic leaf of Vexor, an independent, Zig-native Solana validator, carved out as a standalone, dependency-free Zig package. Every module in this repository is std-only: zero C FFI, zero vendored .a/.so archives, zero external build graph. It implements the primitives a Solana validator needs to verify transaction signatures, run alt_bn128/Poseidon syscalls, and compute the account lattice hash that feeds bank_hash. It also ships the Known-Answer-Test (KAT) corpus that proves each one byte-exact against independent reference implementations.
This is not a from-scratch, never-before-seen cryptography library, and it does not claim to be. It is a byte-compatibility artifact: code written in Zig, informed by reading Agave, Firedancer Ballet, and Syndica's Sig as reference implementations and differential oracles, reimplementing their behavior, and gating every output against published/independent vectors. See NOTICE for the full, file-by-file attribution ledger. It is the authoritative source for "who wrote what," and this README summarizes it but does not replace it.
Status: pre-1.0, testnet-grade, not independently security-audited. Read Honest limits before depending on this for anything that moves value.
- What it is
- Why it exists / who it's for
- Feature matrix
- Repository layout
- Install
- Usage
- Verification & correctness
- The
@prov:provenance-anchor convention - Honest limits / what this is not
- License & attribution
- Roadmap
- Contributing
zolcrypt packages the exact set of cryptographic routines a Solana validator's execution path needs, with no dependency outside the Zig standard library:
- Ed25519, consensus-path signature verification (
verifyStrict, matching Agave's actualSignature::verify()), the same strict verifier with an AVX-512 IFMA fast path for the shred path, and a pure-Zig RFC 8032 signer. - BN254 /
alt_bn128: G1/G2 point addition and scalar multiplication, compression/decompression, and the optimal-ate pairing check, implementing the same byte contract as the Solanasol_alt_bn128_*syscalls. - Poseidon-BN254: the permutation behind the
sol_poseidonsyscall. - LtHash: the 2048-byte / 1024-lane
u16lattice hash used to accumulate account state intobank_hash,@Vector-accelerated. - BLAKE3: a thin wrapper over
std.crypto.hash.Blake3(theaccountLtHashhot path). - SHA-256-backed core types:
Hash,Pubkey,Signature. - Precompiles: parsers/verifiers for the three Solana signature-verification precompile programs:
Ed25519SigVerify111...,KeccakSecp256k1..., andSecp256r1SigVerify...(SIMD-0075).
Provenance, in one sentence: this code was extracted from Vexor's src/vex_crypto/ leaf, the stack that ships in Vexor's production binary and votes on Solana testnet today, and is republished here unmodified as a standalone Zig package, not copied at runtime from any other project. Some numeric floors (a field-arithmetic backend, a fiat-crypto artifact, a KAT corpus) are carried verbatim from Apache-2.0/MIT-licensed upstream projects and are credited as such; the orchestration, API surface, group law, pairing, Poseidon parameter conversion, and precompile logic are Vexor-authored. The full breakdown is in NOTICE.
Pure-Zig, FFI-free Solana cryptography is not something you can zig fetch today as a standalone unit. It typically lives buried inside a validator's or client's source tree, coupled to that project's internal types, allocator conventions, and build graph. zolcrypt exists to close that gap:
- Validator and client authors who want a Solana-crypto leaf they can vendor into a Zig project without pulling in a C toolchain,
blst,libsecp256k1, or any other native dependency. That matters for reproducible builds, sandboxed/BPF-adjacent build environments, and trivial cross-compilation (the whole point ofzig build -Dtarget=...is broken the moment you link a prebuilt.a). - Solana tooling authors (indexers, explorers, fuzzers, replay tools) who need byte-exact
alt_bn128/Poseidon/Ed25519/precompile semantics in Zig without re-deriving them from Rust source. - ZK / applied-crypto Zig developers who want a BN254 tower (Fp/Fp2/Fp6/Fp12), pairing, and Poseidon implementation they can read, audit, and build on, with an existing byte-exact KAT harness as a starting point.
- Anyone auditing Vexor who wants the crypto leaf isolated from the rest of the validator (networking, banking stage, gossip, ...) so it can be read and tested as a self-contained ~15.9k-line unit.
The unifying theme is FFI-free by construction: no blst, no libsecp256k1, no OpenSSL, no build-time C compiler requirement anywhere in this package.
| Primitive | File(s) | Status | Verified against | Notable perf |
|---|---|---|---|---|
| Ed25519 consensus verify | ed25519.zig (verify) → ed25519/root.zig (verifyStrict) |
Shipping | matches Agave's Signature::verify(), which resolves to verify_strict; differential-tested against dalek/ed25519-speccheck vectors |
AVX-512 IFMA (vpmadd52) on znver4; generic @Vector fallback on other targets |
| Ed25519 strict verify (shred path) | ed25519.zig (verifyShred) → ed25519/root.zig (verifyStrict) |
Shipping | 3-way stdlib-cofactored/strict/lenient matrix, dalek verify_strict semantics |
AVX-512 IFMA (vpmadd52) on znver4; generic @Vector fallback on other targets |
| Ed25519 batch strict verify | ed25519/root.zig (verifyBatchStrict) |
Shipping (internal API) | same 3-way matrix | double-base scalar-mul (doubleBaseMul) + w-NAF |
| Ed25519 sign | ed25519.zig (sign) → ed25519/root.zig (signPureZig) |
Shipping | byte-identical to std.crypto RFC 8032 signing |
pure-Zig, FFI-free |
| Ed25519 KAT corpus | ed25519/wycheproof.zig, ed25519/kat.zig |
Shipping | Google Project Wycheproof EDDSA vectors | — |
| Ed25519SigVerify precompile | ed25519_precompile.zig |
Shipping | Agave verify_strict acceptance semantics |
— |
| KeccakSecp256k1 precompile | secp256k1.zig |
Shipping | Agave ECDSA-recover + Ethereum-address acceptance semantics | — |
| Secp256r1SigVerify precompile (SIMD-0075) | secp256r1.zig |
Shipping | Agave low-S / P-256 acceptance semantics | — |
| BN254 G1/G2 add, scalar-mul | bn254/curve.zig, bn254/root.zig |
Shipping | Firedancer test_bn254.c, go-ethereum EIP-196/197, py_ecc |
— |
| BN254 optimal-ate pairing | bn254/pairing.zig |
Shipping | Firedancer test_bn254.c, go-ethereum EIP-196/197 pairing fixtures |
batched Miller loop (BATCH_MAX) |
| BN254 compress/decompress | bn254/curve.zig (G1.compress/decompress, G2.*) |
Shipping | solana-bn254 v3.2.1 published constants (flag=0, flag=1 negated, point-at-infinity) | — |
| BN254 base-field reduction | bn254/fiat_fp.zig |
Shipping | fiat-crypto machine-generated proof (verbatim artifact) | Montgomery form |
| Poseidon-BN254 | bn254/poseidon.zig, bn254/poseidon_params.zig |
Shipping | Firedancer test_poseidon.c (single-input LE/BE, N-ones N=1..12, FLIST chain) |
width up to 12 inputs (state width 13) |
| LtHash (lattice hash) | lthash.zig |
Shipping | Agave lattice-hash account-accumulator semantics | @Vector(32, u16) → vpaddw/vpsubw on AVX-512 |
| BLAKE3 | blake3.zig |
Shipping | std.crypto.hash.Blake3 (pure-Zig; no FFI backend remains) |
— |
| SHA-256 core types | hash.zig |
Shipping | std.crypto.hash.sha2.Sha256 |
— |
| BLS12-381 | — | Not included | — | deliberately excluded; see Honest limits |
zolcrypt/
├── build.zig # module "zolcrypt" (src/root.zig) + one zig build test-* step per KAT root
├── build.zig.zon # package manifest — name, version, minimum_zig_version, fingerprint
├── LICENSE # Apache-2.0
├── NOTICE # full, file-by-file attribution ledger (authoritative)
├── README.md # this file
├── BUILDING.md # toolchain, build targets, optimize modes, cross-compilation
├── TESTING.md # test architecture, coverage categories, per-gate guide
└── src/
├── root.zig # public module surface: re-exports + aggregate `test { ... }` root
├── hash.zig # Hash / Pubkey / Signature (32/64-byte extern structs, SHA-256) + KATs
├── lthash.zig # LtHash — 2048-byte / 1024-lane u16 lattice hash + algebraic-law tests
├── blake3.zig # std.crypto.hash.Blake3 wrapper + official BLAKE3-team vectors
├── ed25519.zig # verify() / verifyShred() / sign() / generateKeypair() — Vexor's call-site API
├── ed25519/
│ ├── root.zig # Vexor-authored: doubleBaseMul, w-NAF tables, verifyStrict,
│ │ # verifyLenientCofactorless, verifyBatchStrict, signPureZig
│ ├── avx512.zig # AVX-512 IFMA (vpmadd52) field backend [credited floor, via Sig]
│ ├── generic.zig # portable @Vector fallback [credited floor, via Sig]
│ ├── crosscheck.zig # generic-vs-AVX512-IFMA backend cross-consistency + std oracle
│ ├── fuzz.zig # adversarial/edge/fuzz: malformed inputs never panic, garbage → reject
│ ├── wycheproof.zig # Google Wycheproof EDDSA KAT corpus (150-vector, machine-generated)
│ └── kat.zig # wycheproof strict-verdict matrix + ACCEPT round-trips + 3-way matrix
├── ed25519_precompile.zig # Ed25519SigVerify111... precompile parser/verifier
├── secp256k1.zig # KeccakSecp256k1... ECDSA-recover + eth-address precompile
├── secp256r1.zig # Secp256r1SigVerify... (SIMD-0075) P-256 precompile
├── bn254.zig # backend-dispatch leaf: pure_zig g1/g2 add·mul, pairing, compress, poseidon
└── bn254/
├── root.zig # alt_bn128 syscall surface (Firedancer Ballet fd_bn254_* byte contract)
├── field.zig # Fp / Fp2 / Fp6 / Fp12 tower
├── curve.zig # G1 / G2 group law, compress/decompress
├── pairing.zig # optimal-ate Miller loop + final exponentiation
├── fiat_fp.zig # BN254 base-field Fp Montgomery reduction [verbatim fiat-crypto artifact]
├── poseidon.zig # Poseidon-BN254 permutation + poseidonHash()
├── poseidon_params.zig # round constants (ark) + MDS, de-Montgomery'd to normal Fr
├── fuzz.zig # adversarial/edge/fuzz + algebraic group laws: not-on-curve reject, never-panic
└── kat.zig # absolute + independent-oracle byte-exact vectors
Line counts (via wc -l, this revision):
| Group | Files | Lines |
|---|---|---|
Core types / hashes (hash.zig, lthash.zig, blake3.zig) |
3 | 453 |
Ed25519 (ed25519.zig + ed25519/*.zig, incl. crosscheck.zig + fuzz.zig) |
8 | 3,470 |
Precompiles (ed25519_precompile.zig, secp256k1.zig, secp256r1.zig) |
3 | 1,434 |
BN254 + Poseidon (bn254.zig + bn254/*.zig, incl. fuzz.zig) |
10 | 11,544 |
src/ total (incl. root.zig) |
25 | 16,955 |
Build + docs (build.zig, build.zig.zon, LICENSE, NOTICE, README.md, BUILDING.md, TESTING.md) |
7 | — |
(bn254/poseidon_params.zig alone is 7,226 lines — it is machine-derived round-constant/MDS-matrix data, not hand-written logic; bn254/fiat_fp.zig at 2,032 lines is the fiat-crypto-generated field reduction, also machine output. The hand-authored orchestration code is a small fraction of the raw line count.)
Requires Zig 0.15.2 (pinned in build.zig.zon via minimum_zig_version; this package is not tested against other Zig versions).
From your project root, using Zig's package manager:
zig fetch --save git+https://github.com/DavidB-77/zolcrypt.gitThis adds an entry to your build.zig.zon:
.dependencies = .{
.zolcrypt = .{
.url = "git+https://github.com/DavidB-77/zolcrypt.git#<commit>",
.hash = "...", // filled in by `zig fetch`
},
},For local/monorepo development, a plain path dependency also works:
.dependencies = .{
.zolcrypt = .{ .path = "../zolcrypt" },
},Then wire it into your build.zig:
const zolcrypt_dep = b.dependency("zolcrypt", .{ .target = target, .optimize = optimize });
exe.root_module.addImport("zolcrypt", zolcrypt_dep.module("zolcrypt"));git clone https://github.com/DavidB-77/zolcrypt.git
cd zolcrypt
zig build test --summary allSee BUILDING.md for toolchain, build targets, optimize modes, and cross-compilation, and TESTING.md for the test architecture, coverage categories, and per-gate guide.
All examples below use the actual public surface exposed by src/root.zig — nothing here is aspirational.
const zc = @import("zolcrypt");// Strict verification, matching Agave's actual Signature::verify(). This is
// the verifier Vexor's transaction/gossip/keypair paths use.
const ok: bool = zc.verify(&sig_64_bytes, &pubkey_32_bytes, message_bytes);
// equivalently: zc.ed25519.verify(...)const kp = zc.ed25519.generateKeypair(); // { public: [32]u8, secret: [64]u8 }
const sig64 = zc.ed25519.sign(kp.secret, "hello");
try std.testing.expect(zc.verify(&sig64, &kp.public, "hello"));// 128-byte input: two 64-byte (x,y) G1 points, packed per the endianness flag.
var out: [64]u8 = undefined;
const wrote: bool = zc.bn254.g1Add(&out, input_128_bytes, true /* big_endian */);
// wrote == false means a soft failure (bad length / not on curve) —
// the syscall layer above this package maps that to `return 1`, not a panic.// `in` is N * 192-byte (G1||G2) pairs. out[0] (or out[31] if big_endian) is
// 1 iff the product of pairings equals the identity in GT, else 0.
var out: [32]u8 = undefined;
const wrote = zc.bn254.pairing(&out, pairing_input_bytes, true);var digest: [32]u8 = undefined;
const inputs: []const []const u8 = &.{ input_a_32_bytes, input_b_32_bytes };
const wrote = zc.bn254.poseidonHash(&digest, inputs, true /* big_endian */, false /* enforce_padding */);var lt = zc.LtHash.init(); // 1024 × u16, zeroed
lt.wrappingAdd(&other_lthash); // per-lane wrapping add (vpaddw on AVX-512)
lt.wrappingSub(&removed_lthash); // per-lane wrapping sub (vpsubw on AVX-512)
const bytes: *const [2048]u8 = lt.asBytes();// Each precompile module exposes the same shape: verify(data, all_instr_datas) PrecompileError!void
try zc.ed25519_precompile.verify(this_instruction_data, all_instruction_datas_in_tx);
try zc.secp256k1.verify(this_instruction_data, all_instruction_datas_in_tx);
try zc.secp256r1.verify(this_instruction_data, all_instruction_datas_in_tx);const h = zc.Hash.compute(some_bytes); // SHA-256
const pk = zc.Pubkey.fromBytes(pubkey_bytes);
const sig = zc.Signature.fromBytes(sig_bytes);Note on the Ed25519 "strict" API surface:
verifyStrict,verifyLenientCofactorless,verifyBatchStrict,doubleBaseMul, andsignPureZiglive insrc/ed25519/root.zigand are used internally byed25519.zig(verify,verifyShred, andsign), butsrc/root.zigdoes not currently re-export theed25519/root.zigsubmodule itself, so they are not part of the package's external public API in this revision, onlyzc.ed25519.verify,.verifyShred,.sign, and.generateKeypairare reachable from outside the module. This is a real gap if you need the strict/batch verifier standalone; see Roadmap.
The KATs are the point of this package. A Solana validator cannot afford a single wrong bit in these routines — one differing byte in alt_bn128, Poseidon, ed25519 verification, or the account lattice hash forks the node off consensus. So zolcrypt ships the vectors that prove parity, not just the code, and every primitive above is exercised by zig build test.
For every KAT, the test asserts that the pure-Zig output is bit-for-bit identical to a published reference output — not "close," not "same result modulo encoding," but the exact same byte sequence a reference implementation (Firedancer, go-ethereum, py_ecc, solana-bn254/ark-bn254, Google Wycheproof) produces for the same input. For BN254 in particular, three independent-lineage oracles (go-ethereum in Go, py_ecc in Python from the Ethereum Foundation, and solana-bn254/ark-bn254 in Rust — no shared code, authorship, or ancestry between them or with Vexor's Zig) are checked against the same vectors, which is materially stronger evidence than self-consistency against a single reference.
Confirmed by running the suite in this revision (zig build test --summary all, zig-0.15.2, cores 28-31, nice -n 19 / taskset):
Build Summary: 21/21 steps succeeded; 214/215 tests passed; 1 skipped (Debug)
Build Summary: 21/21 steps succeeded; 270/270 tests passed (ReleaseSafe, -Doptimize=ReleaseSafe)
The single Debug "skipped" is the AVX-512 IFMA generic-vs-IFMA cross-check arm, correctly skipped on the self-hosted backend (which does not select the vpmadd52 kernels); under ReleaseSafe it runs and passes. The gap between 215 and 270 is the avx512.zig IFMA kernels' own inline declarations being pulled into the compiled graph when the backend is selected, plus std.testing.refAllDecls-style declaration coverage that expands under LLVM, the same source-level tests, exercised more thoroughly at the higher optimize level. Both Debug and ReleaseSafe must be green; only ReleaseSafe exercises the production shred-verify AVX-512 backend (see TESTING.md).
Per-module breakdown (Debug run):
| Test artifact | zig build step |
Tests | What it proves |
|---|---|---|---|
test-root |
zig build test-root |
88 | Aggregate: SHA-256/Hash/Pubkey/Signature KATs + LtHash algebra + BLAKE3 vectors + all re-exports |
test-ed25519 |
zig build test-ed25519 |
13 | ed25519.zig sign/verify round-trip |
test-ed25519-core |
zig build test-ed25519-core |
14 | Pure-Zig ed25519 core: Wycheproof + ACCEPT + 3-way strictness matrix |
test-ed25519-crosscheck |
zig build test-ed25519-crosscheck |
13 (+1 skipped) | Generic-vs-AVX512-IFMA backend cross-consistency + std.crypto oracle |
test-ed25519-fuzz |
zig build test-ed25519-fuzz |
18 | Adversarial/edge/fuzz: malformed inputs never panic, garbage → reject |
test-ed25519-precompile |
zig build test-ed25519-precompile |
19 | Ed25519SigVerify precompile parser + batch verify |
test-secp256k1 |
zig build test-secp256k1 |
12 | secp256k1 ECDSA-Keccak recover + eth-address precompile |
test-secp256r1 |
zig build test-secp256r1 |
10 | secp256r1 (P-256) SIMD-0075 precompile + low-S |
test-bn254 |
zig build test-bn254 |
14 | BN254/alt_bn128 group ops, pairing, compression, Poseidon byte-exact vectors |
test-bn254-fuzz |
zig build test-bn254-fuzz |
13 | BN254 adversarial/edge/fuzz + algebraic group laws: not-on-curve reject, round-trips, never-panic |
| Total | zig build test |
214 (+1 skipped) |
See TESTING.md for the full test architecture and the coverage categories (KATs, curve/structural edge cases, negative/adversarial parser inputs, seeded fuzz harnesses, algebraic group laws, round-trip consistency, and the generic-vs-AVX512-IFMA cross-check), and BUILDING.md for toolchain and optimize-mode details.
Live output from the Ed25519 and BN254 KAT gates (test-root / test-bn254, Debug run), reproduced verbatim:
[KAT a] wycheproof strict: 138/138 vectors matched
[KAT b] ACCEPT round-trip: 64 keypairs signed+verified
[KAT b/lenient] stdlib-cofactored ACCEPTs 2 cofactored cases (local disagreement documented)
[KAT c] 3-way semantic matrix: 9 vectors pinned (stdlib-cofactored/strict/lenient)
[ABS g1_add] 2 FD vectors byte-exact
[ABS g1_mul] 2 FD vectors byte-exact
[ABS pairing] generator-pair=not-one, empty=one OK
[IND g1_add] 4 go-ethereum EIP-197 vectors byte-exact
[IND g1_mul] 6 go-ethereum EIP-197 vectors byte-exact
[IND pairing] 5 go-ethereum EIP-197 vectors byte-exact
[IND g2_add] 4 py_ecc-computed vectors byte-exact
[IND g2_mul] 5 py_ecc-computed vectors byte-exact
[IND compress] solana-bn254 v3.2.1 g1/g2 (flag=0 + flag=1 negated + infinity) round-trips byte-exact
[ABS poseidon] single-input LE+BE byte-exact
[ABS poseidon] N-ones N=2..12 byte-exact
[ABS poseidon] FLIST 12-step chain byte-exact
On the "138/138" line: ed25519/wycheproof.zig carries the full, machine-generated Google Project Wycheproof EDDSA corpus (numberOfTests: 150 per its header comment). The strict-verdict KAT loop in ed25519/kat.zig iterates every group and skips (via a decode-guarded continue) groups whose public-key encoding cannot be parsed to a fixed 32-byte key — this is a property of a handful of the 150 upstream Wycheproof groups (which include deliberately malformed-encoding negative-test groups at the group level, not the signature level), not a gap in vector coverage of parseable vectors. 138 vectors are decoded and asserted byte-for-byte; 0 are silently ignored past the decode stage.
Sources cited by the corpus, per NOTICE and the KAT file headers:
- Google Project Wycheproof (Apache-2.0) — EDDSA test vectors,
ed25519/wycheproof.zig(machine-generated, "DO NOT EDIT" banner intact). - Firedancer Ballet (
firedancer-io/firedancer, Apache-2.0) —test_bn254.c/test_poseidon.cabsolute vectors; thefd_bn254_*/fd_ed25519_verifybyte contracts as differential oracles. - go-ethereum (Apache-2.0/LGPL) — EIP-196/197
bn256Add/bn256ScalarMul/pairing precompile fixtures, as an independent-lineage oracle. - py_ecc (Ethereum Foundation, MIT) — Python-computed G2 vectors, independent-lineage oracle.
- solana-bn254 v3.2.1 / ark-bn254 (Apache-2.0) — authoritative Agave wire/serialization semantics (endianness, flag bytes, length) and compression-constant vectors.
- light-poseidon v0.2.0 (Apache-2.0) / circomlib v2.0.5 (GPL-3.0, parameters/spec reference only) — Poseidon round constants and MDS matrix provenance, converted out of Montgomery form for byte-identical output.
- Agave (
anza-xyz/agave, Apache-2.0) — the consensus acceptance ground truth for precompile behavior (SIMD-0075 for secp256r1).
# Pin to cores 28-31, low CPU/IO priority, exactly as this README's own numbers were produced:
nice -n 19 ionice -c3 taskset -c 28-31 zig build test --summary all
# Individual gates:
nice -n 19 ionice -c3 taskset -c 28-31 zig build test-ed25519-core
nice -n 19 ionice -c3 taskset -c 28-31 zig build test-ed25519-crosscheck # generic-vs-IFMA cross-check
nice -n 19 ionice -c3 taskset -c 28-31 zig build test-ed25519-fuzz
nice -n 19 ionice -c3 taskset -c 28-31 zig build test-bn254
nice -n 19 ionice -c3 taskset -c 28-31 zig build test-bn254-fuzz
nice -n 19 ionice -c3 taskset -c 28-31 zig build test-secp256k1
nice -n 19 ionice -c3 taskset -c 28-31 zig build test-secp256r1
nice -n 19 ionice -c3 taskset -c 28-31 zig build test-ed25519-precompile
nice -n 19 ionice -c3 taskset -c 28-31 zig build test-ed25519
# ReleaseSafe (matches the 270/270 figure above; the ONLY mode that runs the
# AVX-512 IFMA generic-vs-IFMA cross-check on an IFMA-capable host):
nice -n 19 ionice -c3 taskset -c 28-31 zig build test -Doptimize=ReleaseSafe --summary all
# Formatting gate:
zig fmt --check src build.zigEach zig build test-* step maps 1:1 to a KAT root file/artifact, so a regression in one primitive fails loudly and specifically rather than as an opaque aggregate failure.
Several modules carry inline @prov:crypto.<domain> comment tags at the top of security-relevant blocks (@prov:crypto.bn254, @prov:crypto.ed25519-precompile, @prov:crypto.lthash, @prov:crypto.secp256k1, @prov:crypto.secp256r1 — 89 occurrences across bn254.zig, ed25519_precompile.zig, lthash.zig, secp256k1.zig, and secp256r1.zig in this revision). These are provenance/behavior-spec anchors used inside the Vexor validator tree to tie a specific code region back to the acceptance-semantics rule it implements (e.g. "n_sigs == 0 is rejected" or "G2 mul requires a subgroup check, G2 add does not"), so that a future edit to that region is reviewed against the rule it's implementing, not just against the diff. They are documentation/traceability markers, not executable code — there is no build-time enforcement of @prov: tags in this standalone package (that tooling lives in the Vexor validator tree this was extracted from). Treat them as "why this line is shaped this way" breadcrumbs when reading the source.
- No BLS12-381. The BLS12-381 syscall module in Vexor's source tree (
bls12_381.zig/bls12_381_syscall.zig) links the vendoredblstC library via FFI. It was deliberately not extracted into this package —zolcryptis FFI-free by construction, and a pure-Zig BLS12-381 implementation does not exist here yet. See Roadmap. - Zig 0.15.2 pinned, not portable across Zig versions.
build.zig.zonsetsminimum_zig_version = "0.15.2"and the package is developed/tested only against that exact toolchain. It has not been validated on other 0.15.x point releases, 0.14.x, or nightly Zig. - Testnet-grade, pre-1.0 (
version = "0.1.0"). This is the code a validator runs on Solana testnet. It has not been run, or specifically hardened, for mainnet-beta value-at-risk conditions as a standalone library outside that validator's operational envelope. - Not independently security-audited. The correctness evidence here is KAT-based (byte-exact match against published/independent vectors) and "lives in a validator that holds consensus parity" — that is strong differential and operational evidence, but it is not a substitute for a professional, independent cryptographic security audit. None has been performed on this package as a standalone artifact.
- The Ed25519 "strict"/batch API is not externally exposed.
verifyStrict,verifyBatchStrict,verifyLenientCofactorless,doubleBaseMul, andsignPureZigexist insrc/ed25519/root.zigbut are not re-exported bysrc/root.zigin this revision — see the note in Usage. - The consensus Ed25519 path is strict verification, matching Agave.
ed25519.zig'sverify()routes toverifyStrict. An earlier revision of this code routed the consensus path through the cofactoredstd.cryptoverifier instead, on the claim that Agave accepts small-order-R signatures strict verification rejects. That claim was wrong: Agave's actualSignature::verify()resolves toverify_strict. The incident that motivated the earlier, mistaken choice (a livebank_hashdivergence in Vexor, documented ined25519.zig's source comments) came from a separate FFIverify_strictimplementation's bug, not from strictness as a policy.verify()was corrected on 2026-07-29 and is now strict by default, matching the cluster. - Machine-generated components are carried, not hand-verified line-by-line.
bn254/poseidon_params.zig(7,226 lines of round constants/MDS matrices) andbn254/fiat_fp.zig(2,032 lines, fiat-crypto's generated Montgomery reduction) are data/proof artifacts pinned by the KAT corpus, not independently re-derived by hand for this package. - No published performance benchmarks yet. The AVX-512 IFMA Ed25519 path and the
@Vector-accelerated LtHash are architecturally fast (the point of using intrinsics/vectorization at all), but no formal benchmark suite or numbers are published in this repository as of this revision.
zolcrypt is licensed under the Apache License, Version 2.0 — see LICENSE.
Copyright (c) 2026 the Vexor authors.
This package reimplements behavior from, and in some components carries verbatim floors from, the following Apache-2.0 (and in one parameters-only case, GPL-3.0-referenced) upstream projects:
- Agave (
anza-xyz/agave) — consensus acceptance ground truth - Firedancer Ballet (
firedancer-io/firedancer) — syscall byte contracts, differential oracle, parameter sources - Syndica's Sig (
syndica/sig) — credited verbatim floor fored25519/avx512.zig,ed25519/generic.zig(dalekcurve25519-dalekIFMA backend, reached via Sig), anded25519/wycheproof.zig - fiat-crypto (
mit-plv/fiat-crypto) — verbatim, machine-generated, formally-verified BN254 base-field Montgomery reduction (bn254/fiat_fp.zig), tri-licensed MIT/Apache-2.0/BSD-1-Clause - Google Project Wycheproof — EDDSA KAT corpus
- go-ethereum and py_ecc — independent-lineage BN254 oracles
- solana-bn254 v3.2.1 / ark-bn254 — wire/serialization semantics and compression-constant vectors
- light-poseidon v0.2.0 and circomlib v2.0.5 (GPL-3.0, parameters/spec reference only, no code linked) — Poseidon round-constant/MDS provenance
NOTICE is the authoritative attribution record. It documents, per module, exactly what is Vexor-authored orchestration versus what is a credited verbatim floor, why each floor is carried rather than rewritten, and which upstream project each differential oracle/KAT vector traces back to. Read it before redistributing, forking, or relying on this package's provenance claims — this README summarizes it but NOTICE governs.
"Agave", "Firedancer", "Sig", and "Solana" are trademarks of their respective owners; this project's use of their names is for accurate technical attribution only.
- Pure-Zig BLS12-381. Replace the FFI/
blst-linked BLS module that was excluded from this extraction with a from-scratch pure-Zig implementation, KAT-gated the same way as the BN254 tower. - More curves / precompiles as Solana SIMDs add them (this package tracks Agave 4.2-era syscall/precompile surface as of this revision).
- Independent, professional security audit of the package as a standalone artifact (distinct from Vexor's own internal review process).
- Published performance benchmarks for the AVX-512 IFMA Ed25519 path, the BN254 tower, Poseidon, and the LtHash accumulator, across representative hardware (currently only validated functionally, not benchmarked, in this repository).
- Externally expose the Ed25519 strict/batch API (
verifyStrict,verifyBatchStrict,verifyLenientCofactorless,signPureZig,doubleBaseMul) fromsrc/root.zigso callers outside Vexor can use the strict/batch verifier without reaching intosrc/ed25519/root.zigdirectly. - 1.0.0 once the above (BLS coverage, an external audit, and benchmark numbers) land —
0.1.0is intentionally conservative about what "done" means for a package whose entire purpose is not being byte-wrong.
This package tracks Vexor's live, in-production crypto leaf. Correctness changes here are expected to be gated the same way the existing code is: KAT-first, byte-exact against an independent published reference, with zig build test passing under both Debug and ReleaseSafe before a change is proposed. If you're adding a new primitive, follow the existing per-module zig build test-<name> pattern in build.zig so it gets its own named, individually runnable gate rather than being folded silently into test-root.
Apache-2.0. Part of the Vexor ecosystem — vexornode.xyz.