19 Commits
Author SHA1 Message Date
zeekayandHanzo Dev 5493e3a2ed quantumvm: a validator key parses its secret once and keeps it
Sign now asks the key for its ML-DSA form instead of rebuilding one per
call. A key that arrives as bytes parses on first use and reuses that
key for every signature after; a freshly generated key already holds its
parsed form. A secret that will not parse fails closed on every call.

Takes crypto v1.20.5, where a private key copies the secret it is given
and hands back a copy, so the bytes a caller persists out of a generated
key stay readable for as long as the caller holds them.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-15 00:52:02 -07:00
zeekayandHanzo Dev 3e85a4dc82 quantumvm/stamper: batch verification must check the same things, for the right stamp
The accelerated batch path re-implemented two things the sequential path already
did, and got both wrong.

1. It re-listed the block-correspondence fields itself and omitted ReceiptsRoot,
   which verifyStampSync checks. A stamp carrying a forged receipts root was
   therefore accepted whenever accel was available and the batch cleared
   DilithiumBatchThreshold, and refused otherwise — acceptance decided by host
   hardware. Both paths now call stampMatchesBlock, the one definition.

2. The hybrid post-quantum leg read signDataSlice[0] for every stamp:
   signDataSlice is indexed by BATCH POSITION while indices maps position to stamp
   index, and the loop discarded the position. Every hybrid stamp's SLH-DSA
   signature was verified against the FIRST batch entry's signing bytes. That both
   false-rejects honest stamps and, since a batch submitter chooses what entry zero
   contains, accepts a signature made over data the stamp does not commit to.

Proven against the pre-fix logic: a correctly signed hybrid stamp at batch
position 1 failed; a stamp carrying a signature over another stamp's bytes passed;
a forged ReceiptsRoot passed the batch field list.

Tests: TestHybridBatchVerifiesEachStampAgainstItsOwnData,
TestHybridBatchRejectsSignatureOverAnotherStampsData,
TestStampMatchesBlockCoversReceiptsRoot.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-29 16:48:10 -07:00
zeekayandHanzo Dev af5096e6fe quantumvm: count distinct validators toward both finality thresholds
AddCoronaSignature and AddBLSSignature appended caller-supplied signatures with no
signer check, and TryFinalize compares len(signatures) against q.threshold. One
peer resending the same signature therefore drove the count to the threshold on
its own. Proven: three calls carrying one validator's signature left three entries
in the list.

The Corona leg is the sharp end: TryFinalize finalizes it on count alone and
verifies none of the signatures, unlike the BLS leg which aggregates and verifies.
So a single peer satisfied the post-quantum half of quantum finality by itself.

Insertion for both legs now goes through addBLS/addCorona, which record one
signature per ValidatorID, and SignBlock's own contribution goes through the same
door instead of appending directly.

Tests: TestOneValidatorCannotReachCoronaThreshold,
TestDistinctValidatorsReachCoronaThreshold, TestOneValidatorCannotReachBLSThreshold.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-29 16:48:10 -07:00
zeekayandHanzo Dev 9ec41cf150 Native-ZAP struct-is-wire for the four straggler VMs (aivm/keyvm/quantumvm/dexvm)
Completes the "one and only one way" wire migration: every VM in this repo now
serializes blocks and txs through luxfi/zap struct-is-wire at fixed field
offsets — no encoding/json, no hand-rolled big-endian, no cursor codec.

- aivm: Block + AIVertex + nested CIntent native-encoded. Fixes a latent
  data-loss bug — AIVertex had unexported fields, so encoding/json silently
  marshalled it as {}; the native encoder round-trips every field.
- keyvm: Transaction (signing preimage = SigningBytes(), excludes Auth/Sig;
  full wire = signing || sig object, so the signed bytes stay a genuine prefix
  and authenticate() re-derives a byte-identical preimage) + Block.
- quantumvm: Block + BaseTransaction. Block wire is the quantum-signature
  preimage (deterministic fixed offsets, ordered tx list).
- dexvm: block envelope (txs were already ZAP). Preserves UnixNano timestamps,
  deterministic tx order, and content-addressed carried fills.

Hardening from the adversarial crypto review (must-holds all verified: no
keyvm signature malleability/replay, no aivm CIntent id-forgery/escrow tamper,
no dexvm ordering/fill tamper, all parsers fail closed):

- keyvm (M1): make the wire strictly canonical. zap follows the root offset
  and ignores unreferenced padding inside a message's declared size, so a twin
  buffer could decode to identical fields with a different hash (id-malleability).
  ParseTransaction now binds the id to the re-serialized (canonical) form and
  rejects any non-canonical input at the door — exactly one byte-string
  authenticates per logical tx. Regression test: the padded twin is rejected.
- quantumvm (M2): derive block + tx ids as sha256(Bytes()), matching the other
  three VMs. The prior ids.ToID(parent||height) over 40 bytes (and ids.ToID over
  the >=32-byte tx wire) silently yielded ids.Empty for every block/tx,
  collapsing the block store and tx pool to a single slot. The block id is no
  longer stored in the wire, so the invariant id == sha256(Bytes()) holds
  unconditionally. Regression tests: ids are non-Empty and collision-distinct.

Not in scope (tracked separately, fail-closed today): aivm RewardPerOperator is
escrowed but not bound by ComputeIntentID — a pre-existing design gap that needs
a coordinated A-side + C-side intent-id preimage bump before any non-fail-closed
CCommitVerifier ships.

Builds + tests green under the canonical CGO=0 -mod=readonly recipe; go.mod/go.sum
are the go mod tidy canonical set (indirect deps resolved forward, all within
major). Cryptographer verdict: SAFE TO PUBLISH.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-16 13:44:24 -07:00
zeekayandHanzo Dev 5c72db8860 quantumvm: enforce LP-0130 §6 — no user-payable blockspace on Q-Chain
Flip the Q-Chain fee gate from FlatPolicy (user-fee metering) to the
committee-only fee.NoUserTxPolicy sentinel. Finality-cert inclusion is
a validator obligation paid via P-Chain reward distribution; a fee
market on Q would make finality hostage to blockspace pricing — the
exact failure mode LP-0130 §6 eliminates. Consensus-internal cert
aggregation reaches txPool.AddTransaction directly and is unaffected.

Tests updated: policy is the NoUserTxPolicy sentinel and IssueTx
refuses every user tx (zero-fee, floor-fee, and 1000x floor) with
ErrChainAcceptsNoUserTxs. go test ./quantumvm/ passes; build + vet
clean.

Closes the top divergence from the 2026-07-03 LP-vs-code audit.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-03 12:32:41 -07:00
zeekay 40d29ef0f6 fix(quantumvm): drop trusted-dealer dual-key keygen; build against consensus v1.25.35
InitializeDualThreshold called consensus quasar.GenerateDualKeys, a
trusted-dealer keygen (one process mints+holds every validator's BLS+Corona
share, defeating threshold security). Consensus relocated that helper to
test-only (keygen_testsupport_test.go) as corona-genesis hardening, so
production chains no longer compiles against it.

The method was dead: zero callers anywhere, and it already discarded the
generated signer (_ = signer, used only for two log lines) and inited fake
v0/v1/v2 validator IDs. The live Quasar bridge signs through the consensus
core with per-validator keys (ML-DSA fallback on the VM paths); real
validators join via AddValidator. Removing it is a no-op at runtime and
restores the build against consensus v1.25.35. Any future per-epoch group
key must come from a dealerless DKG, never a trusted dealer.
2026-06-26 22:26:24 -07:00
zeekay 349e27b10c consensus parity: quantumvm joins the linear cert path; dexvm doc fix
quantumvm/vm.go: remove GetEngine() so the chain manager routes Q-Chain through
the linear consensuschain cert path (the same deterministic 2/3-stake BFT
certificate finality as C/D/P), not the undriven DAG engine. quantumvm already
implements the full chain.ChainVM/BlockBuilder surface; dropping GetEngine is the
whole change. Adds the _ chain.ChainVM + _ consensuschain.BlockBuilder asserts.

dexvm/factory.go: correct the stale 'Quasar consensus' comment — dexvm finalizes
via the linear cert path (Photon->Wave->Focus + 2/3-stake cert), same as C-Chain.
2026-06-25 16:07:07 -07:00
zeekay 563a3fd454 scrub Liquidity branding + corona→corona (OSS brand hygiene) 2026-06-10 23:44:07 -07:00
zeekay b8a2a5c4dc chains: scrub private-repo leakage from GPU bridges
OSS public chains module must not reference the private GPU plugin
implementation by repo name or filesystem path. Two leak types fixed:

1. Hard compile-time dependency in quantumvm:
   `#cgo CFLAGS: -I${SRCDIR}/../../../lux-private/gpu-kernels/include`
   Vendor the public ABI v14 header (backend_plugin.h + crypto.h, 1475
   LOC total) into chains/internal/luxgpu/include/lux/gpu/ and point
   CFLAGS at the in-tree path. Plugin DSO is still dlopen'd at runtime
   — only the public C ABI surface is vendored.

2. Soft leakage — `LUX_PRIVATE_GPU_KERNELS_DIR` env vocabulary, dev-tree
   probe paths to ~/work/lux-private/gpu-kernels/build/..., prose
   mentions of "lux-private/gpu-kernels" in package comments.
   All replaced with `LUX_GPU_PLUGIN_DIR` (universal env) and generic
   "GPU plugin" prose.

Bridges affected: aivm, bridgevm, dexvm, quantumvm, thresholdvm.
All 139 tests PASS post-scrub under both build tags. No functional
behavior change — only path / env / prose.
2026-06-05 15:46:00 -07:00
zeekay fc0a2410db quantumvm: wire GPU plugin substrate via ABI v14 vtbl dlopen+dlsym
Adds four Go files to chains/quantumvm so the Q-Chain VM can call into
the lux-private/gpu-kernels plugin's batched ML-DSA verify, ML-DSA sign,
and SLH-DSA verify slots without a build-time pkg-config dependency:

* backend.go            cross-build types: Backend enum, GPUBackend
                        interface, MLDSAMode + MLDSA65* size constants,
                        SLHDSAVariant enum + per-variant pk/sig widths
                        (FIPS 204 / FIPS 205), ErrGPUNotAvailable,
                        AutoBackend(). Build-tag-free so vm.go can
                        reference the surface regardless of CGO_ENABLED.
* quantumvm_gpu.go      cgo dlopen probe at init() in order
   (cgo)                cuda -> hip -> metal -> vulkan -> webgpu,
                        resolving lux_gpu_backend_init and verifying
                        the ABI v14 cookies (abi_version + vtbl_size)
                        plus the load-bearing op_mldsa_verify_batch
                        slot before opening a LuxBackendContext. Three
                        vtbl-slot wrappers dispatch through C
                        trampolines into op_mldsa_verify_batch,
                        op_mldsa_sign_batch, and the SHAKE-128f /
                        SHAKE-192f variants of op_slhdsa_verify_batch.
* quantumvm_gpu_nocgo.go symmetric noGPUBackend stub returning
                        ErrGPUNotAvailable on every method so the
                        package surface is identical under !cgo.
* quantumvm_gpu_test.go round-trip test: dlopens the configured
                        plugin (LUX_GPU_PLUGIN_DIR override or default
                        loader path), generates an ML-DSA-65 keypair +
                        signs a 64-byte digest via circl, then submits
                        the triple through MLDSAVerifyBatch and asserts
                        results[0] == true. Cleanly SKIPs when no
                        plugin loaded or when the backend returns
                        NOT_SUPPORTED for op_mldsa_verify_batch (e.g.
                        plugins built without LUX_GPU_LINK_CRYPTO).

The probe is header-only: cgo CFLAGS points at
${SRCDIR}/../../../lux-private/gpu-kernels/include for the v14 vtbl
layout, but the .dylib / .so is dlopen'd at runtime - no pkg-config,
no static link, no luxcpp/install dependency. Existing quantumvm
vm.go, quantum/signer.go, and quantumvm/quasar.go are untouched;
consumers opt in explicitly when ready. Both 'go build ./quantumvm/...'
and 'CGO_ENABLED=1 go build ./quantumvm/...' are green.

Test output with LUX_GPU_PLUGIN_DIR pointing at a freshly-built
libluxgpu_backend_vulkan.dylib:
  --- PASS: TestAutoBackend_Probes (0.00s)          [backend=vulkan]
  --- PASS: TestMLDSAVerifyBatch_RoundTrip (5.56s)  [backend=vulkan,
            op_mldsa_verify_batch honest verify -> true]
  --- PASS: TestMLDSAVerifyBatch_LengthMismatch (0.00s)
  --- PASS: TestMLDSAVerifyBatch_NonMLDSA65Skips  (0.00s)
2026-06-05 14:59:54 -07:00
zeekay 9d1722e220 quantumvm: gate user tx on FeePolicy (MinTxFee floor)
Add Fee() to the Transaction interface and introduce VM.IssueTx as
the canonical user-tx admission point. The FeePolicy gate refuses
zero-fee tx before they reach the parallel quantum verification
pool. Consensus-internal callers bypass via txPool.AddTransaction.
2026-05-21 17:09:16 -07:00
zeekay f70ba504fd remove detailed patent-claims docs (relocated to lux-private/patents)
Detailed invention disclosures are sensitive pre-filing material. Moved to
lux-private/patents to preserve international filing rights (EU/JP/KR/CN
absolute-novelty rule). Cross-ref: github.com/lux-private/patents/bundles/
2026-05-19 11:30:50 -07:00
zeekay b07e70ec2c patent-claims: novelty triage drafts (attorney-prep, not filed) 2026-05-19 10:51:05 -07:00
zeekay 38a694bde4 Consolidate VMs into single chains module; cevm Metal anchor + V4 dispatch
VM consolidation (one module, one place only):
- Removed per-VM go.mod/go.sum/VERSION from {aivm,bridgevm,dexvm,evm,
  graphvm,identityvm,keyvm,oraclevm,quantumvm,relayvm,thresholdvm,zkvm}
- All VMs now compile under github.com/luxfi/chains root module
- aivm/, dexvm/, identityvm/, keyvm/, oraclevm/ factory.go + vm.go updated
  for AccelHost wiring

cevm Go-side (evm/cevm/):
- cevm.go, cevm_cgo.go, cevm_nocgo.go: ExecuteBlockV4(backend, threads,
  txs, ctx, state) with StateAccount snapshot
- cevm_secp256k1.go: BatchRecoverSenders Metal LDFLAGS
- cevm_secp256k1_metal_anchor_darwin.{c,go}: anchor to keep linker from
  dropping libsecp256k1_metal.a
- cevm_secp256k1_nocgo.go: stub for non-cgo builds
- plugin.go, fetch-luxcpp.sh, luxcpp-SHA256SUMS, LUXCPP_VERSION:
  pinned luxcpp consumption
- evm/cevm/parallel/parallel.go: BlockExecutor adapter calls
  cevm.ExecuteBlockV4 with state snapshot built from txs+statedb

Quantum/ZK witness:
- quantumvm/quasar_witness.go, zkvm/zwitness.go

go.mod: removed dead `replace github.com/ethereum/go-ethereum => luxfi/geth`
directive (caused dual-path conflict after math semver bump; no remaining
ethereum/go-ethereum imports in source). go mod tidy clean.

Tests: TestBatchRecoverSenders PASS through Metal anchor (cevm package).
2026-05-05 10:17:49 -07:00
zeekay 2a86eaedde fix(submodules): resolve build/test failures across 6 chains
- evm: bump precompile to v0.5.12 + fhe to v1.8.0 + gpu to v0.31.1
  (gpu v0.30.0 had unresolved C.mlx_* CGO symbols)
- aivm, bridgevm, quantumvm: go mod tidy
- thresholdvm, zkvm: bump genproto to v0.0.0-20260217215200-42d3e9bedb6d
  to resolve ambiguous googleapis/api/annotations import

All 12 chains now build and tests pass with GOWORK=off.

Refs #248
2026-04-28 02:51:06 -07:00
zeekay ccca40e63b fix: dexvm VMID type + quantumvm RPC name
- dexvm.VMID: [32]byte → ids.ID (consistent with other 10 VMs)
- quantumvm RPC service: "qvm" → "quantumvm" (matches package + dir)

Removes last vestiges of the old short-name convention.
2026-04-13 05:49:35 -07:00
zeekay 8045450815 feat: move all VM implementations into chains/
VMs now live in ONE place: chains/<name>/ owns the full implementation.
Previously split across node/vms/<name>/ (impl) + chains/<name>/main.go
(plugin wrapper). Now consolidated.

New layout:
  chains/<name>vm/*.go              — package <name>vm (VM code)
  chains/<name>vm/cmd/plugin/main.go — package main (plugin binary)
  chains/<name>vm/go.mod             — module github.com/luxfi/chains/<name>vm

Moved 11 VMs: aivm, bridgevm, dexvm, graphvm, identityvm, keyvm,
oraclevm, quantumvm, relayvm, thresholdvm, zkvm.

External callers now import github.com/luxfi/chains/<name> directly.
2026-04-13 05:27:00 -07:00
zeekay b74f5eba49 refactor: rename packages bvm/gvm/qvm/tvm/zvm to match dir names
Consistent naming: directory = package = binary.
- bvm → bridgevm
- gvm → graphvm
- qvm → quantumvm
- tvm → thresholdvm
- zvm → zkvm

Also: delete teleportvm/ and servicenodevm/ chain wrappers.
- teleportvm was duplicate of bridgevm+relayvm+oraclevm (separated chains)
- servicenodevm was renamed to sessionvm and lives at github.com/luxfi/session

One name, one package, one place.
2026-04-13 05:15:42 -07:00
zeekay ea6e37dc24 feat: VM plugin monorepo — 14 independent binaries
Each VM builds as a standalone binary that the Lux node loads via
--plugin-dir. Node no longer bakes optional VMs in-process.

VMs: evm, dexvm, aivm, bridgevm, graphvm, identityvm, keyvm,
oraclevm, quantumvm, relayvm, servicenodevm, teleportvm,
thresholdvm, zkvm.

All 13 node-dependent VMs compile and report version correctly.
EVM requires CGo (luxcpp) — builds in CI only.
2026-04-12 13:05:45 -07:00