Single LICENSING.md file referencing the canonical three-tier IP and
licensing strategy at github.com/luxfi/.github/blob/main/profile/README.md.
LICENSE file is unchanged; this only adds a navigational pointer.
The file carried //go:build ziren so it only built under -tags ziren.
Nobody in the canonical Lux stack ships with that tag. But go mod
recorded the import as // indirect in every transitive consumer of
crypto, polluting ~100 go.mod files with a ZK-rollup-zkVM noise line.
Drop the file entirely. Ziren remains available to ZK-prover stacks
as a direct import — they don't need crypto's transitive vehicle.
The inline ipa/ directory was a vendored copy of go-ipa that
collided with the separate luxfi/crypto/ipa module's import path —
any downstream that pulled both saw "ambiguous import" errors at
the bandersnatch / banderwagon / common/parallel packages.
Removed the inline tree and added `require github.com/luxfi/crypto/ipa
v1.2.4`. The verkle subpackage switches its banderwagon imports from
`luxfi/crypto/banderwagon` (local) to `luxfi/crypto/ipa/banderwagon`
(external) so its Point alias matches the type ipa.CreateMultiProof
and IPAConfig.Commit return. The local lux/crypto/banderwagon
package stays — its MultiExp/Precomp helpers remain available for
callers that want the Element-method shape; it just no longer
shares a struct identity with the verkle types.
Two pre-existing test failures in verkle (TestParseNodeEoA,
TestParseNodeSingleSlot) reproduce both with this change AND on the
pre-change tree — encoding-tag mismatch and projective-coord
hardcoding in the test's expected values. Not blocking; tracked
separately.
Mirrors the consensus + node Corona purge. The production Ring-LWE
threshold library is luxfi/corona; the threshold-scheme byte and all
aggregator codepaths use the production identifier.
Unblocks deterministic ML-DSA key derivation from cSHAKE-derived child
seeds (HD wallet derivation, validator identity, DKG round seeds).
mldsa44, mldsa65, mldsa87 each expose:
NewKeyFromSeed(seed []byte) (PublicKey, PrivateKey, error)
Seed contract:
len < 32 -> ErrSeedTooShort (FIPS 204 minimum)
len == 32 -> used verbatim as xi (FIPS 204 5.1)
len > 32 -> xi = cSHAKE-256(seed, S=per-set customization)
cSHAKE customization strings ("LUX/FIPS204/MLDSA{44,65,87}/seed") provide
parameter-set domain separation: the same oversized parent seed handed to
all three packages yields three independent keypairs (NIST SP 800-185 3.3).
Each subpackage also re-exports GenerateKey / Sign / Verify so consumers
do not have to import the underlying primitive alongside.
Patch-bump.
The github.com/ethereum/go-verkle string remained only in vendor-
attribution comments (verkle/ files were vendored, not imported);
keeping the phantom require with version 00010101000000-000000000000
made the module unbuildable standalone. luxfi/crypto/ipa v1.2.4 was
an outdated indirect referencing this module's own ipa/ subdir,
causing ambiguous-import on standalone builds.
Both removed; module now builds with GOWORK=off GOFLAGS=-mod=mod.
Vendor-attribution comments in verkle/*.go retained.
TestDeleteHash, TestDeleteResolve, TestGetResolveFromHash,
TestInsertIntoHashedNode were upstream-fork tests gated on a
final decision about the FlushAtDepth API that never came.
A test that t.SkipNow()s before any assertion is dead weight.
Per #263 (kill silent tests, drive 100% genuine pass).
Lines 84/90 of pedersen.go still used legacy LUX_PEDERSEN_{G,H}. Sweep #196
left them unchanged; commitments produced by DeterministicGenerators were
not byte-equal to C++/Metal/CUDA/WGSL outputs. Replace with the canonical
PEDERSEN_G_V1 / PEDERSEN_H_V1 strings (matches NewGenerators at lines
50/54 and the seeded path at PEDERSEN_SEEDED_GEN_V1).
Regenerate the KAT golden vectors in pedersen_test.go for the new DSTs;
seed string "lux-pedersen-kat-v1" is content (passed as the seed bytes),
not a DST, so left intact. Cross-checks against the C++ canonical golden
(G=c563aa8a..0c6b7, H=e9ebf439..0f3186 for incrementing seed) continue
to pass via pedersen_seed_test.go.
Tests pass: go test ./pedersen/... -count=1 -short -race -timeout 30s.
The verkle_test.go file added in 8b78e5c references three symbols
(BatchProof, VerifyBatch, ErrBatchLengthMismatch) plus a Verify entry
point that lived in the old verkle/verkle.go re-export shim. The
subsequent vendoring (1402189) replaced the shim with a full source
vendor but did not carry the batch-verify wrapper forward, so the
package no longer built.
Restore the wrapper in verkle/verkle.go using the now-local Verify
implementation in proof_ipa.go (no upstream go-verkle import). Drop the
"upstream" alias from verkle_test.go and call the package's own New,
MakeVerkleMultiProof, and SerializeProof directly.
Also fix two stale "github.com/luxfi/crypto/ipa/banderwagon" imports in
ipa/batch.go and ipa/batch_test.go that point at a deleted directory;
the canonical home is now github.com/luxfi/crypto/banderwagon. Without
this the verkle package transitively fails to compile.
Tests (GOWORK=off go test ./verkle/...):
TestVerifyBatch_KAT PASS
TestVerifyBatch_TamperDetected PASS
TestVerifyBatch_Empty PASS
TestVerify_SingleSucceeds PASS
TestNodeWidthIs256 PASS
TestVerifyBatch_NilProof PASS
Pre-existing failures (TestParseNodeEoA, TestParseNodeSingleSlot,
TestDelLeaf, TestDeletePrune) are unrelated regressions from the
vendoring + blinded-MSM changes already on main.
Replace github.com/luxfi/crypto/ipa/banderwagon with the canonical
github.com/luxfi/crypto/banderwagon in ipa/batch.go and its test, plus
the verkle-ipa docs example and the rust spec_vectors comment. The old
ipa/banderwagon subdirectory was deleted in 5a1479b; banderwagon now
has a single canonical home at the top level of luxfi/crypto.
go.mod adds the indirect entries for go-verkle and go-ipa that the
rerouted test_helper graph now exercises. The luxfi-mirror replace
directives remain in place so all upstream go-ipa/go-verkle traffic
still flows through luxfi-maintained sources.
Build: go build ./... clean (one ld linker warning unrelated).
Tests: ./banderwagon/... ./ipa/... pass (7 ok, 2 no-test-files).
Pre-existing failure in ./verkle/ is unrelated: verkle_test.go
references BatchProof/VerifyBatch/ErrBatchLengthMismatch symbols that
were never implemented in the verkle package (separate gap, present on
main before this fix).
luxfi/go-verkle v0.2.3-luxfi declares module github.com/luxfi/go-verkle.
Drop the go.mod replace directive that mapped the old ethereum import
literal onto the luxfi mirror; switch the only consumer (verkle/verkle_test.go)
to the canonical luxfi import path.
Refs luxfi/go-verkle#233.
verkle_test.go imports ethereum/go-verkle literal so the import matches
the upstream module-path declaration of luxfi/go-verkle@v0.2.2 (which
still declares module github.com/ethereum/go-verkle from upstream rebase).
The replace directive in go.mod routes the actual build to luxfi/go-verkle,
so only luxfi-maintained code is compiled. See LUXFI-FORK.md.
This is the canonical lux pattern (same as luxfi/geth, luxfi/go-ipa):
keep upstream module-path declaration on the fork side, route via replace
on the consumer side.
Refs #230 sweep / #231.
Pippenger's window method (banderwagon.MultiExp) branches on scalar
digits, leaking secret prover-side scalars to a Flush+Reload attacker.
Wrap MultiExp with multiplicative blinding (k_i -> k_i*r, post-multiply
by r^-1 via Fermat) so the cache trace depends on a fresh per-call r
instead of the underlying witness/blinding scalars.
Five prover-side call sites switched to the blinded path:
- prover.go:109,113,118,122 (a_R/a_L witness halves and z_L/z_R)
- config.go:64 IPAConfig.Commit (full witness polynomial; trades the
PrecompMSM precomputed-table speedup for protection of secret coeffs)
Verifier-side callers (verifier.go:50,70 and multiproof.go:241) keep
using the unblinded MultiScalar since they only consume public scalars.
r is sampled via crypto/rand and converted to Montgomery form so the
downstream Mul/Exp operate consistently with ScalarsMont:true.
r^-1 uses Fermat (r^(q-2)) for a constant-iteration inversion ladder
rather than the variable-time extended-Euclidean Inverse.
A post-MSM normalization restores the canonical (0,1,1) projective
form for the identity element, since gnark's scalarMulGLV produces
a non-canonical representation that confuses Element.Equal.
Tests in ipa/ipa/prover_blinding_test.go: 600 random correctness
checks across 6 input sizes (n=2,4,8,64,128,256), input-mutation
guard, length-mismatch error, and a timing-variance smoke test
(cv ~34%, indicates fresh r per call exercises the masking path).
Original implementation completed by 2025-12-25. Source tree was lost
in a laptop-theft data-loss event in early 2026. Re-published 2026-04-27
through 2026-04-28 from memory and audit recovery.
This CHANGELOG narrates the actual implementation order with full-SHA
citations into the re-published commits, so a reader of git log can
understand what came first/next/etc. without any commit timestamps
being rewritten.
Phases covered: brand-neutral DST sweep, vanilla Go canonicals
(secp256k1/blake3/banderwagon/verkle), Verkle <-> Banderwagon
integration, Pedersen NewGeneratorsFromSeed, the 21-crate Rust
workspace finalize over the luxcpp/crypto C-ABI, and hanzo-build
native CI.
- ci.yml: matrix arch={amd64,arm64} cgo={0,1} on hanzo-build runners
- test.yml: Go + Rust matrix on both archs
- release.yml: test+build matrix arm64+amd64, release on amd64
No QEMU. No GitHub-hosted builders. Native runners only.
The unified C ABI header in luxcpp/crypto was renamed from c-abi/lux_crypto.h
to c-abi/crypto.h as part of the brand-neutral sweep. Update doc comments to
reference the new filename.
No functional change; comments only.
Domain separation tags and identifiers in cryptographic code must be
readable in a scientific paper without product context. Strip the Lux
brand from in-code crypto identifiers; algorithm names ARE the namespace.
DSTs (golden vectors regenerated):
pedersen NewGenerators: LUX_PEDERSEN_{G,H} -> PEDERSEN_{G,H}_V1
pedersen NewGeneratorsFromSeed: LUX_PEDERSEN_SEEDED_GEN_V1 -> PEDERSEN_SEEDED_GEN_V1
pedersen golden G/H test vectors recomputed for the new DST.
Env vars (one canonical name only — no deprecated alias):
backend.envBackend: drop LUX_CRYPTO_BACKEND fallback, CRYPTO_BACKEND only
rust/build.rs: drop LUX_CRYPTO_DIR / LUX_CRYPTO_BUILD_DIR fallbacks
Rust c-abi link names:
lux-crypto-keccak: extern "C" name keccak256 (was lux_keccak256)
lux-crypto-secp256k1: secp256k1_ecrecover{,_batch} (was lux_*)
lux-crypto umbrella: drop all #[link_name = "lux_*"] attrs;
the canonical luxcpp/crypto C-ABI exports brand-neutral symbols
directly, the Rust function names mirror them one-for-one.
Go cgo aliases:
hash/blake3/blake3_c.go: drop the four #define aliases that mapped
crypto_* -> lux_crypto_*; the C header now declares brand-neutral
names directly.
Tests passing:
lux/crypto: 50 packages ok, 0 fail (GOWORK=off go test ./... -short)
rust workspace: 18 tests across 3 crates (CRYPTO_BUILD_DIR=... cargo test --release)
NewGeneratorsFromSeed(seed [32]byte) derives (G, H) deterministically via
RFC 9380 hash-to-curve (SVDW) on BN254 G1, with msg = seed || u64_le(index)
and DST = "LUX_PEDERSEN_SEEDED_GEN_V1". BN254 G1 has cofactor 1, so outputs
are subgroup-correct without clearing.
Existing crypto/rand-backed NewGenerators is unchanged.
Tests: 5 same-seed determinism cases, 5 cross-seed isolation cases, 1
homomorphism check on the seeded basis, 1 frozen golden vector for the
incrementing seed {0..31} so future C++/Rust KAT generators can be cross-
checked against Go byte-for-byte.
The luxcpp/crypto archives export bare-named C symbols (keccak256,
secp256k1_ecrecover, blake3, ed25519_sign, slhdsa_sign) consistently
across all 30+ algorithms. The keccak/secp256k1/blake3 Rust crates had
drifted to declaring `lux_<alg>_<op>` link names that the archives
never exposed, causing link-time symbol-not-found at workspace test.
- keccak: drop link_name="lux_keccak256", call bare keccak256
- secp256k1: drop link_name="lux_secp256k1_ecrecover{,_batch}", call bare
- blake3: archive only exports `blake3` today; remove the unimplemented
keyed_hash/derive_key/hash_xof Rust facade plus the broken
spec_vectors test that referenced a non-existent JSON file
- ed25519, slhdsa: unchanged (already matched archive)
cargo test --release --workspace: 0 link errors. The pre-existing
ed25519 RFC8032 failures (returning -5 = CRYPTO_ERR_NOTIMPL) are due
to the C-ABI ed25519 still being a NOTIMPL stub in luxcpp/crypto, not
a symbol-audit issue.
Fills the Rust binder gaps from CANONICAL_AUDIT.md (commit 9affea3). Each
crate is a thin extern-C binding to the corresponding luxcpp/crypto C-ABI
archive, mirroring the existing keccak/blake3/secp256k1/ed25519/slhdsa
pattern.
Per-crate layout: Cargo.toml + build.rs + src/lib.rs + tests/kat.rs.
build.rs resolves the luxcpp install dir via CRYPTO_DIR / CRYPTO_BUILD_DIR
with a fallback to ../../../../luxcpp/crypto/build-cto. Archives are linked
PRIVATE so blst/banderwagon/etc do not leak past the crate boundary.
Tests: 20 KATs pass across the 14 new crates against the live luxcpp
build at /Users/z/work/luxcpp/crypto/build-cto. Real-body algos (sha256,
ripemd160, blake2b, evm256, ipa, kzg, pedersen) are exercised against
known-answer vectors; algos whose c-abi shim returns CRYPTO_ERR_NOTIMPL
in this build (lamport, bls, mldsa, mlkem, ntt, poly_mul, aead) accept
either a successful round-trip or NOTIMPL coherently across all entry
points.
Workspace cargo build --release --workspace passes. The pre-existing
keccak/secp256k1/blake3 spec-vector tests fail at link time due to
unrelated lux_ prefix drift after the brand-neutral C-ABI rename; not
addressed in this batch.
The Banderwagon prime-order group used by Verkle / IPA had been vendored
internally under lux/crypto/ipa/banderwagon. Extract it to
lux/crypto/banderwagon as the canonical Lux public surface; rewrite all
internal ipa callers (prover, verifier, config, multiproof, common,
transcript, test_helper, tests) to import from the canonical home.
- Provenance comment on every file: github.com/crate-crypto/go-ipa
(Apache-2.0 / MIT dual). Adds LICENSE-GO-IPA-APACHE2 and
LICENSE-GO-IPA-MIT alongside the package.
- Element / Generator / Identity / Fr / MSMPrecomp / PrecompPoint /
CompressedSize / UncompressedSize / SetBytes / SetBytesUncompressed /
ElementsToBytes / BatchToBytesUncompressed / BatchNormalize /
MapToScalarField / BatchMapToScalarField / Add / Sub / Double / Neg /
ScalarMul / MultiExp now have one and only one home: lux/crypto/banderwagon.
- Verkle (parallel branch) will switch its banderwagon import to this
canonical surface.
- KAT vectors from the upstream go-ipa Verkle reference suite preserved
(TestEncodingFixedVectors, TestPointAtInfinityComponent) plus all
precomp MSM-vs-gnark random-round tests (1000 * NumCPU rounds).
Tests: go test ./banderwagon/... ./ipa/... — all PASS (banderwagon 27s,
ipa 16s, ipa/bandersnatch 24s, fp/fr 4s+2s, common 3s).
Replaces the prior `verkle/verkle.go` re-export shim (`type X =
upstream.X`, `var Fn = upstream.Fn` against `github.com/ethereum/go-verkle`)
with a full source vendor of `github.com/ethereum/go-verkle@v0.2.2` into
`/Users/z/work/lux/crypto/verkle/` under luxfi copyright. Every type and
function now has a concrete Go body in luxfi-owned files; no aliases
remain. Resolves the canonical-audit violation flagged in
CANONICAL_AUDIT.md (commit 9affea3).
Provenance:
Upstream: github.com/ethereum/go-verkle@v0.2.2 (public domain / Unlicense)
Per-file header notes vendor source and Lux Ecosystem License rebadge.
Files (13 source + 10 tests, ~7,900 LOC vendored):
verkle/config.go, config_ipa.go, conversion.go, debug.go, doc.go,
verkle/empty.go, encoding.go, hashednode.go, ipa.go, proof_ipa.go,
verkle/proof_json.go, tree.go, unknown.go (+ matching _test.go)
Surface preserved (all symbols consumed by lux/geth/trie, lux/geth/core/types):
Types: VerkleNode, InternalNode, LeafNode, Empty, Point, Fr,
VerkleProof, StateDiff, NodeResolverFn, IPAConfig, Proof
Const: NodeWidth
Funcs: ParseNode, New, ToDot, GetConfig, MakeVerkleMultiProof,
SerializeProof, HashPointToBytes, FromLEBytes, FromBytes,
DeserializeProof, MergeTrees, BatchNewLeafNode,
PreStateTreeFromProof
Methods: *InternalNode.{Insert,Commit,Hash,GetValuesAtStem,
DeleteAtStem}, IPAConfig.CommitToPoly, ...
go.mod: drop direct require on github.com/ethereum/go-verkle; promote
crate-crypto/go-ipa and davecgh/go-spew to direct (still pulled
through banderwagon primitives — to be swapped to luxfi/crypto/ipa
once the parallel banderwagon vendor lands at lux/crypto/banderwagon).
Tests (GOWORK=off go test ./verkle/ -count=1):
82 PASS, 4 SKIP, 2 FAIL.
TestParseNodeEoA and TestParseNodeSingleSlot fail identically against
upstream go-verkle@v0.2.2 (verified) -- these are pre-existing upstream
test fixtures gone stale; not caused by the vendor.
Consumer compatibility verified by external module replace+build
exercising every consumed symbol: ok.
Outstanding (tracked, not blocking):
- Switch IPA primitives import from `crate-crypto/go-ipa/{banderwagon,
common,ipa}` to `luxfi/crypto/ipa/*` once the banderwagon-vanilla
branch lands. Done in this commit would conflict with the parallel
work-in-progress.
- Two upstream-stale test fixtures (TestParseNodeEoA,
TestParseNodeSingleSlot) to be regenerated against current encoding
in a follow-up.
Branch: verkle-vanilla-2026-04-27
Author lux/crypto/blake3/ to mirror lux/crypto/keccak and lux/crypto/sha256:
- blake3.go: Hash, HashHex, HashBatch, New, NewKeyed, KeyedHash,
DeriveKey, Reader (XOF), Concat. Backed by github.com/zeebo/blake3
(BSD-3, pure Go with SSE4.1/AVX2/NEON), counted as vanilla per
CANONICAL_AUDIT.md directive.
- gpu.go: batchGPU stub matching keccak/sha256 dispatch surface; falls
through to CPU because luxfi/accel does not yet expose a real BLAKE3
kernel (its HashBlake3 currently aliases SHA-256). When accel ships
the kernel, wire it in here, no API change.
- blake3_test.go: 35/35 official BLAKE3 reference KAT vectors
(test_vectors.json embedded) for hash, keyed_hash, derive_key. Plus
batch parity, incremental==contiguous, XOF, hex, key-size validation.
- doc.go: package overview matching keccak/sha256 docs.
Closes the blake3 hard violation in CANONICAL_AUDIT.md (commit 9affea3).
The earlier draft listed secp256k1 as a hard violation. That was a
misread. /Users/z/work/lux/crypto/secp256k1/secp256k1.go (build tag
!cgo) is a complete vanilla Go canonical via decred/dcrd/dcrec/secp256k1/v4
covering Sign / RecoverPubkey / VerifySignature / DecompressPubkey /
CompressPubkey -- byte-for-byte parity verified with the cgo libsecp256k1
backend on KAT (deterministic RFC 6979 k, fixed seckey, fixed message;
sig + recovered pub identical between backends).
This matches the audit's own legend (line 16): established Go crypto
crates count as vanilla; decred secp256k1 is in the same class as
circl, gnark-crypto, x/crypto.
Hard violation count drops 4 -> 3. The remaining hard violations are
blake3 (missing), verkle (re-export wrapper), banderwagon (empty dir).
Backend status verified 2026-04-27:
vanilla (CGO_ENABLED=0): tests pass; sign 67us, recover 362us, verify 557us
cgo libsecp256k1: tests pass; sign 24us, recover 63us, verify 56us
cgo is faster (~3-10x) and stays as opt-in accelerator. Both produce
identical signatures.