audit 2026-06: TEE + GPU + public-permissionless-chain safety

Production-readiness audit of Magnetar v1.2 across four
dimensions: (1) public-permissionless-chain safety, (2) TEE
integration story, (3) GPU acceleration story, (4) canonical-name
positioning across luxfi/*. APPROVED for v1.2 deployment on Lux
public-permissionless chains under the documented threat model
(per-validator standalone unconditional; THBS-SE under
legacy-compat profile; strict-PQ chains route through sibling
luxfi/threshold/protocols/slhdsa-tee t-of-n attested-combiner
pool).

New documents:

  - AUDIT-2026-06.md --- comprehensive audit per dimension.
    Slashable evidence is correctly extractable
    (VerifyThbsSeEvidence is pure third-party). Slot-bound
    commit-and-reveal is sound (Class-N1 byte-equality pinned by
    TestSlhdsaInternal_ByteEqualToCirclSign). Static-corruption
    bound = Shamir t-of-n; adaptive bound = same with
    proactive-resharing lift proposed for v1.3. Public combiner
    is safe against malicious shares (commit re-derivation +
    ThbsSeShareEvidence). Residual microsecond-residency window
    of master bytes in derivedMaterial is honestly documented.
    Canonical-name verification: no conflicting "SLH-DSA
    threshold" name exists across luxfi/*; "Magnetar" is the
    single canonical name (precompile slot 0x012207, dispatcher
    pkg/thresholdd/magnetar.go, ZAP wire schemas/zap/magnetar_*,
    bridge consumer, crypto/slhdsa/gpu.go references).

  - TEE-INTEGRATION.md --- canonical design + deployment matrix.
    Profile gate (magnetarRefuseUnderStrictPQ) is ONE function in
    ONE place. AMD SEV-SNP is production today; TDX + NRAS are
    stubs tracked at luxfi/mpc#222 stages 2-3. NVIDIA
    Confidential Computing (H100/H200/B200) integration is a
    KnownIssuers map update once cc/attest/nras.go ships.
    Operator-side wiring reference: configureMagnetarStrictPQ
    composes ReleaseGate + hsm.Provider + ApprovalProvider into
    a CombinerPool with Threshold=2, RotationWindow=60s.

  - GPU-PORT-PLAN.md --- v1.3 work item MAGNETAR-GPU-PORT-V13.
    Four batched SHAKE256-based FIPS 205 hash-tree kernels at
    lux-private/gpu-kernels/ops/crypto/slhdsa/ (CUDA + HIP +
    Metal + Vulkan + WGSL) sit on top of the existing
    shake256/sha3_256/keccak256 Keccak-f[1600] permutation
    family. Estimated 16x sign throughput at batch=64 on Apple
    M1 Max Metal, 130x at batch=256 on NVIDIA H100. Threshold
    for GPU dispatch mirrors crypto/slhdsa.LastValidatorBatchTier
    pattern. NOT required for consensus-rate signing; for
    throughput consumers (bridge custody, N=100+ aggregate-cert
    verify, slashing-evidence sweep).

Updated:

  - BLOCKERS.md --- three proposed work items added:
    MAGNETAR-GPU-PORT-V13 (v1.3 GPU acceleration),
    MAGNETAR-PROACTIVE-RESHARE-V13 (v1.3 zero-secret refresh
    lifting static-corruption to refresh-window-bounded
    adaptive-corruption), MAGNETAR-APPLE-SE-HSM-V14 (v1.4
    hsm.Provider backed by Apple Keychain SE-only).

  - README.md --- Documents section links the three new specs.

Verification (clean as of audit):

  cd ref/go && GOWORK=off go build ./...          [OK]
  cd ref/go && GOWORK=off go vet ./...            [OK]
  cd ref/go && GOWORK=off go test -count=1 -short \
    -timeout 600s ./pkg/magnetar/...              [ok 192.033s]
  bash scripts/checks/strict-atom-ast.sh          [GATE GREEN]
This commit is contained in:
Hanzo AI
2026-06-03 11:45:40 -07:00
parent d1f76659e4
commit 6a3a8653dd
5 changed files with 1525 additions and 0 deletions
+632
View File
@@ -0,0 +1,632 @@
# Magnetar --- 2026-06 production-readiness audit
Audit performed against Magnetar at tag-equivalent commit `d640d15`
(post v1.2 ship state). Scope: public-permissionless-chain safety,
TEE integration story, GPU acceleration story, canonical-name
positioning across `luxfi/*`. Reviewer: cryptographer agent.
> **TL;DR.** v1.2 is shippable for the per-validator standalone
> primitive on any Lux public-permissionless chain and for the
> THBS-SE permissionless threshold primitive under the
> legacy-compat profile. Strict-PQ chains MUST route through the
> sibling `luxfi/threshold/protocols/slhdsa-tee` package's
> t-of-n attested-combiner pool. The gating discipline is correctly
> decomplected --- one profile gate function, one place, one canonical
> refusal sentinel. The audit identifies four open items below; none
> blocks v1.2 deployment, all are scoped against v1.3 / v1.4.
---
## 1. Public-permissionless-chain safety
### 1.1 Slashable evidence (extractability for permissionless slashing)
**Finding: APPROVED.** Equivocation is made cryptographically
extractable by THBS-SE's slot-bound commit-and-reveal discipline.
Specifically:
- A party's Round-1 broadcast is `D_i = cSHAKE256(r_i || s'_i || tau)`
where `tau = SlotBinding.Encode() || msg || party_id`
(`thbsse.go::deriveThbsSeCommit`). The slot binding hashes
`(chain_id, epoch, slot, height, committee_id, message_domain)`
into the commit. Same slot + different `msg` ⇒ different `tau`
different `D_i` ⇒ third-party `VerifyThbsSeEvidence` confirms the
party committed twice.
- `ThbsSeSlotRecord` persists `MessageDigest + Round1 + Round2`
per slot (`thbsse.go:496-500`). Persisting both rounds is
load-bearing for the slashing chain across restarts ---
digest-only persistence is insufficient.
- `ThbsSeEvidence` is the wire-shaped slashing blob:
`(PartyID, SlotID, prior_R1, prior_R2, new_R1, new_R2,
prior_digest, new_digest)`. `VerifyThbsSeEvidence` (a pure
function with no committee state) re-derives `D_i` from each
reveal under the supplied `bindingPrior` and `bindingNew` and
confirms both digests match.
**Critical correctness pin.** `VerifyThbsSeEvidence` requires
`bindingPrior` and `bindingNew` as inputs (`thbsse.go:609`). The
consensus layer MUST publish both slot bindings on-chain when
slashing --- without them the verifier cannot re-derive the
commits. This is a CONSUMER contract; the magnetar primitive is
self-contained.
**Adversarial-share evidence.** Malformed shares (commit mismatch,
wire-size, slot mismatch) produce `ThbsSeShareEvidence` with three
canonical reasons (`thbsse.go:973-977`). `VerifyThbsSeShareEvidence`
recomputes the expected commit and confirms `ExpectedD != ObservedD`
--- the slashable bit is positive proof the named party broadcast a
malformed reveal. No third-party state needed beyond the slot
binding + message.
### 1.2 State management (stateless SLH-DSA + slot-bound reuse refusal)
**Finding: APPROVED.** SLH-DSA is stateless at the primitive level
(unlike XMSS/Mldsa-with-state); the per-validator `Sign` path has
no internal counter to corrupt. THBS-SE's per-party slot binding
provides the one-time-per-slot enforcement via two layers:
- **Local**: `ThbsSeSlotGuard.Record` raises
`*ThbsSeEquivocationError` if the party tries to sign a
different `msg` under the same `slot_id`. Idempotent same-slot
same-msg replay is permitted (`thbsse.go:716-733`) so a network
retry does not become a slashing event.
- **Protocol-layer**: the slot binding flows into the FIPS 205 `ctx`
string via `ctxFromSlot` (`thbsse.go:299-305`), so even a peer
that bypasses its local guard produces signatures that bind
unambiguously to one slot. Cross-slot replay deterministically
fails verification.
**Soundness of slot-bound commit-and-reveal.** The mask
`r_i ← rng` (Round 1) blinds the share `s'_i = share_i XOR r_i`
in `D_i`'s SHAKE absorb. By the random-oracle model treatment of
cSHAKE256, `D_i` reveals zero bits about `share_i` before Round 2.
At Round 2 reveal, `share_i = r_i XOR s'_i` is recovered by anyone;
the byte-wise XOR over a uniformly-random 96-byte `r_i` is
information-theoretically hiding. The Class-N1-analog byte-equality
of the strict-atom Combine path to single-party FIPS 205
SignDeterministic is pinned by
`TestSlhdsaInternal_ByteEqualToCirclSign` across all three SHAKE
modes.
### 1.3 Adaptive corruption at t-of-n
**Finding: APPROVED FOR STATIC CORRUPTION; ADAPTIVE CORRUPTION HAS A
HONEST GAP TIED TO THE PVSS-DKG MODEL.**
The THBS-SE Combine path is secure under static t-of-n
corruption (the Class-N1 byte-equality theorem in `SPEC.md` §6 +
the EasyCrypt theory at
`proofs/easycrypt/Magnetar_N1_StrictAtom.ec`). Each non-corrupted
party's share is information-theoretically uniform from the
adversary's view (Shamir over GF(257)); the corrupted parties'
`t-1` shares are insufficient to reconstruct.
For adaptive corruption (adversary chooses which parties to
corrupt during execution), the standard threshold-Shamir bound
applies: adaptively corrupting any `t` parties recovers the
master. This is the inherent secret-sharing bound, not a Magnetar
choice. The v1.2 PVSS-DKG (`pvss_dkg.go`) is itself adaptive-secure
in the same sense: as long as fewer than `t` parties' Round-1
states are corrupted, the implicit master remains hidden.
**v1.3 work item (proposed).** Augment the PVSS-DKG with
proactive-resharing (zero-secret refresh against the same group
public key) so adaptive corruption is bounded by the refresh
interval, not the full keypair lifetime. This is the standard
lift; the share envelope shape is forward-compatible.
### 1.4 Combiner safety (anyone-can-combine + malicious shares)
**Finding: APPROVED.** The public combiner is a pure function of
its inputs:
- `Combine` validation order (`thbsse.go:802-957`): slot-mismatch
rejected → wire-size rejected → unmatched-Round1 dropped silently
→ unknown party dropped silently → commit-mismatch produces
`ThbsSeShareCommitMismatch` evidence → the remaining shares are
collected, deduped by NodeID, sorted by `EvalPoint`, and the
first `threshold` are passed to `assembleSignatureBytes`.
- Malicious shares cannot fork the output: shares that pass commit
re-derivation are the unique GF(257) byte-reconstruction of the
master. Two combiners running the same input set produce
byte-identical output (the Class-N1 determinism). Two combiners
with overlapping valid quora produce byte-identical signatures
(any `t` evaluation points determine the Lagrange basis at
`x=0`).
- The combiner DOES touch the FIPS 205 master byte material
transiently in `derivedMaterial` (the SHAKE-expansion output
buffer of the Lagrange-interpolated share vector). The
strict-atom discipline at `thbsse_assemble.go` ensures
(a) no variable in the call graph binds these bytes under any
of the four forbidden FIPS 205 master names
(`SK.seed | SK.prf | sk_seed | sk_prf`); (b) the bytes are
accessed only as positional slices; (c) lifetimes are bounded by
the enclosing function call with defer-zeroize.
**Residual gap (honestly documented):** the microsecond residency
of master bytes in the public combiner's `derivedMaterial`. A
peer-local memory-disclosure adversary (coredump,
`/proc/self/mem`) at exactly the combine moment could observe
them. This is the inherent Cozzo-Smart bound for threshold
hash-based signatures without full MPC over the hash tree. Closed
for the `strict-PQ` chain profile by routing every Combine through
the TEE-attested combiner pool (see §2).
### 1.5 Wire format + verifier interoperability
**Finding: APPROVED.** MAGS / MAGG wire codec (v0.5.1, commit
`1c84519`) is canonical and stateless. `VerifyBytes(gkBytes, msg,
sigBytes)` and `VerifyBytesCtx(gkBytes, msg, ctx, sigBytes)` are
pure dispatch into circl's FIPS 205 verifier. The headline
byte-identity claim (`TestMagnetar_Wire_FIPS205Verifiable` +
`TestThbsSE_Wire_FIPS205Verifiable`) is pinned across all three
shipped SHAKE modes (M192s / M192f / M256s).
The precompile at `luxfi/precompile/magnetar/contract.go` slot
`0x012207` is correct: the FIPS 205 SHAKE+SHA2 mode byte space is
fully addressable (`getModeParams`), the gas schedule mirrors
`luxfi/precompile/slhdsa`, and the on-chain `precompileCtx =
"lux-evm-precompile-magnetar-v1"` provides domain separation from
the single-party SLH-DSA precompile.
---
## 2. TEE integration (institutional / strict-PQ surface)
### 2.1 Current state (factual)
The TEE-attested signing path lives at
`luxfi/threshold/protocols/slhdsa-tee/` and is fully wired:
- `slhdsa-tee.Signer` (`signer.go`) is the single-host attested
signer. Composes `kms.ReleaseGate + hsm.Provider +
approval.ApprovalProvider + Config`. The HSM-stored master seed
is unwrapped only inside the attested TEE; the host process
outside the TEE sees only the AEAD-sealed session key, the
wrapped seed ciphertext, and the resulting wire signature.
- `slhdsa-tee.CombinerPool` (`pool.go`) is the t-of-n
attested-combiner registry. Default deployment posture is
`t=2, n=3`; constructor refuses `t<2` (no single-host quorum).
Combine drives each member's full Sign machinery and refuses
byte-divergent quorum output (`ErrMagnetarSignatureDivergence`).
- Profile gate at `luxfi/threshold/pkg/thresholdd/magnetar.go`:
`magnetarRefuseUnderStrictPQ` is ONE function in ONE place;
refuses `Sign` and `Sign_Ctx` under `ProfileStrictPQ` with
`ErrMagnetarNoTEEAttestation`. `Sign_TEE` / `Combine_TEE` are
the only sign surfaces under strict-PQ.
- Chain attestation verifiers at `luxfi/mpc/cc/attest/`:
`sev.go` PRODUCTION (go-sev-guest backed AMD KDS); `tdx.go`,
`nras.go` STUBs returning `ErrNotImplemented` (tracked at #222
stages 2--3). Strict-PQ deployments today MUST use SEV-SNP.
### 2.2 Threat model under strict-PQ
We model an adversary that controls:
- the operator's host process outside the TEE (compromised binary,
malicious operator);
- the operator's at-rest HSM ciphertext (compromised HSM admin,
stolen volume snapshot);
- the network between operator and chain (replay, reordering, drop).
We do NOT model:
- compromised AMD / Intel / NVIDIA vendor signing keys
(defence-in-depth via vendor key rotation);
- physical access to the TEE die during sign (mitigated by
chassis-attest for on-prem; CSP-hosted deployments inherit the
CSP guarantee);
- compromised wall-clock / RotationWindow policy (operator policy,
not cryptographic --- monitor for skew).
### 2.3 NVIDIA Confidential Computing (H100 / H200 / B200) story
**Finding: STUB.** `luxfi/mpc/cc/attest/nras.go` returns
`ErrNotImplemented`; `CombinerPool.Attest` refuses any envelope
routing through `Vendor = "nvidia.nras.v1"`. When the upstream
NRAS verifier ships, the pool's `KnownIssuers` set is the only
knob --- no magnetar-side code change required.
The SLH-DSA Sign path itself is CPU-bound; GPU acceleration is
NOT required for any deployment-rate signing case (per-signature
~ms on modern CPUs). The NVIDIA Confidential Computing story for
Magnetar matters only if a deployment uses GPU-accelerated HASH
batch (the throughput case for high-volume verifier deployments,
e.g. block-time-bound batch verification of N validators'
per-validator standalone signatures). See §3 for that path.
For the SIGNING TEE path, AMD SEV-SNP is the canonical production
substrate. NVIDIA Confidential Compute lands as an additive
substrate when (a) `cc/attest/nras` ships, AND (b) a NVIDIA
Confidential Compute SLH-DSA signer is deployed (a `Signer`
configured to drive the SLH-DSA sign loop inside an H100/H200/B200
CC VM with NRAS attestation). The pool config knob is exactly
`KnownIssuers: {"amd.sev.snp": {}, "nvidia.nras.v1": {}}`.
### 2.4 AMD SEV-SNP for share storage
**Finding: WIRED.** `pool.go` accepts SEV-SNP under
`KnownIssuers = {"amd.sev.snp"}` (the strict default); the
`luxfi/mpc/cc/attest/sev.go` chain validator drives AMD KDS
roundtrips (or `KDSGetter` test injection for offline runs). The
committed Milan fixture at
`pkg/thresholdd/testdata/sev_snp_attestation_milan.bin` +
`sev_snp_vcek_milan.cer` exercises the end-to-end pool drive in
`TestMagnetarCombine_AttestationVerified_AllowsSign`.
### 2.5 Apple Secure Enclave for keys
**Finding: DESIGN-ONLY.** Apple Secure Enclave does not currently
appear in `cc/attest/` as a vendor. The SE's threat model and
attestation surface (DeviceAttestKit, App Attest, Secure Element
attestation via PSE) is fundamentally a device-binding primitive
rather than a server-grade confidential-compute primitive. For
operator-side key storage on Apple Silicon hosts, the canonical
pattern is:
- Use Apple Keychain with `kSecAttrAccessControl =
kSecAccessControlSecureEnclaveOnly` as the at-rest HSM provider
(i.e. an `hsm.Provider` implementation backed by Keychain
+ SE-protected key wrap).
- The CombinerPool's TEE evidence chain still resolves to one of
the supported vendors (SEV-SNP / TDX / NRAS) --- the Apple SE
is a layer BELOW the attestation, not a substitute for it.
This is documented as v1.4 work item
`MAGNETAR-APPLE-SE-HSM-V14`. The `hsm.Provider` interface is the
seam; no magnetar-side change is required.
### 2.6 Recommended deployment matrix
| Chain profile | Sign primitive | TEE substrate | Vendor |
|---|---|---|---|
| `legacy-compat` (default) | per-validator standalone | none required | --- |
| `legacy-compat` (custody opt-in) | `Combine_TEE` (1-of-1 attested) | SEV-SNP | `amd.sev.snp` |
| `strict-PQ` (production today) | `Combine_TEE` (t-of-n pool) | SEV-SNP | `amd.sev.snp` |
| `strict-PQ` (post-#222 stage 2) | `Combine_TEE` (t-of-n pool) | TDX | `intel.tdx` |
| `strict-PQ` (post-#222 stage 3) | `Combine_TEE` (t-of-n pool) | NRAS (H100/H200/B200 CC VM) | `nvidia.nras.v1` |
The `KnownIssuers` map is the single configuration knob; mixed
deployments (e.g. AMD + NVIDIA in one pool) are permitted by
construction.
---
## 3. GPU acceleration (Magnetar's hash-tree throughput story)
### 3.1 Why this matters for Magnetar specifically
Two consumers benefit from GPU acceleration:
1. **Per-validator standalone aggregate-cert verification.** The
`ValidatorBatchVerify` primitive in `standalone.go` is the
bottleneck for block proposers verifying N independently-signed
per-validator FIPS 205 signatures (the canonical Lux quorum
shape, N = 21 typical, N = 100+ in extended deployments). At
SLH-DSA-SHAKE-192s the per-signature CPU verify is ~2ms, so a
N=21 quorum is ~42ms on a single core. GPU batch over the FORS
+ Merkle + WOTS+ public-byte recomputation amortizes well.
2. **THBS-SE high-throughput signing.** The strict-atom Combine
path's `slhSignAtom` walks FIPS 205 §5-§8 sequentially. The
hash-tree expansion is naturally parallelizable: WOTS+ chains,
FORS subtrees, and XMSS layers all have data parallelism
across leaves / chains / layers. For a block-time-bound
high-throughput signing workload (e.g. bridge or institutional
custody signing many independent messages per second), GPU
batch sign is the throughput multiplier.
### 3.2 Current state of `~/work/lux-private/gpu-kernels/`
Inventoried 2026-06-03 at HEAD:
- `ops/crypto/shake256/` — FIPS 202 SHAKE256 XOF on CUDA + HIP +
Metal + Vulkan + WGSL. Permission to share `keccak_f1600.cuh`
permutation across the family. **THIS IS THE SUBSTRATE.**
- `ops/crypto/sha3_256/` — fixed 32-byte SHA3-256 on same 5
backends. Different domain separator (0x06 vs 0x1F) than
SHAKE256 but the same f[1600] permutation.
- `ops/crypto/keccak256/` — Ethereum-domain Keccak (0x01
padding). Different domain separator than SHA3-256 / SHAKE256
but same permutation.
- `ops/crypto/mldsa/` — CUDA only. NTT-bound (Module-LWE), not
applicable to SLH-DSA.
- `ops/crypto/corona/` (Pulsar) — CUDA only. NTT-bound, not
applicable.
- `ops/crypto/attestation/` — CUDA only. The NVTrust GPU-identity
+ attestation report generator (LP-2000). Relevant to the §2
NRAS path but not to SLH-DSA arithmetic.
**Magnetar-specific kernels: NONE EXIST TODAY.** This is the
canonical GPU port gap.
### 3.3 Proposed port plan (v1.3 GPU acceleration)
The FIPS 205 SLH-DSA hash tree decomposes into four kernel
families, all naturally batched by independent input sets and all
already enabled by the f[1600] kernel family above. Each kernel
is a thin wrapper over `keccak_f1600` calling SHAKE256 in the
right modal mode.
#### Kernel 1: `magnetar_wotsplus_chain_batch`
- **Inputs**: batch of `(pkSeed, ADRS, x_base, i, s)` tuples.
- **Output**: batch of `chain(x_base, i, s, pkSeed, ADRS)` outputs
= `F^s(x_base) = SHAKE256(pkSeed || ADRS || ... || x)` chained
`s` times.
- **Parallelism**: across batch elements (independent
invocations). Within one element, the chain is sequential by
construction.
- **Use sites**: `wotsChain` in `slhdsa_internal.go:402`,
`wotsSign:442`, `wotsPkGen:499`. Per-signature each WOTS+
signature requires `wotsLen = 2n + 3` chain computations of
average length `(w-1)/2 = 7.5`; per-hypertree-layer `wotsLen`
per leaf; total per-signature SHAKE absorbs ≈
`2 × d × (2n+3) × 7.5` ≈ 3,000-15,000.
#### Kernel 2: `magnetar_fors_subtree_batch`
- **Inputs**: batch of `(pkSeed, ADRS, leaf_idx, height)`
tuples + the secret PRF callback's outputs (provided as a
batch of `sk[i]` byte sequences).
- **Output**: batch of FORS subtree node values at `(i, z)` for
each tuple.
- **Parallelism**: across batch elements AND, within one element,
across siblings at each height layer.
- **Use sites**: `forsNodeCompute:735`, `forsSign:780`. Per
signature: `k` subtrees of height `a`.
#### Kernel 3: `magnetar_xmss_subtree_batch`
- **Inputs**: batch of `(pkSeed, ADRS, leaf_idx, height)`
tuples + the WOTS+ public-key outputs at the leaf level.
- **Output**: batch of XMSS node values at `(i, z)`.
- **Parallelism**: across batch elements AND within one element
across the `hPrime`-height tree.
- **Use sites**: `xmssNodeCompute:546`, `xmssSign:582`. Per
signature: `d` XMSS trees of height `hPrime`.
#### Kernel 4: `magnetar_hmsg_prfmsg_batch`
- **Inputs**: batch of `(R, pkSeed, pkRoot, msgPrime)` tuples
(for `H_msg`) and `(SK.prf_segment, optRand, msgPrime)` tuples
(for `PRF_msg`).
- **Output**: batched digest / randomizer outputs.
- **Parallelism**: across batch elements.
- **Use sites**: `hMsgPub:341`, `prfMsg` callback. Per signature:
one of each.
#### Why this decomposes cleanly
All four kernels are pure SHAKE256 absorb-and-squeeze with
public-byte inputs (the secret-side `SK.seed` access stays
behind the `prfOut` callback, which is host-only in the
strict-atom discipline). The CPU host walks the FIPS 205
algorithm, dispatching batches of independent SHAKE invocations
to the GPU, and stitching outputs back into the algorithm flow.
This pattern is identical to how
`luxfi/crypto/slhdsa/gpu.go` already dispatches the existing
`luxfi/accel`-based SLH-DSA path for batch verify.
#### Implementation hook into existing infrastructure
`luxfi/crypto/slhdsa/gpu.go` already has the dispatch substrate
(serial / parallel / GPU tier ladder + provenance via
`LastValidatorBatchTier`). The wire is:
1. Land the four kernels above in
`lux-private/gpu-kernels/ops/crypto/slhdsa/` with the same
five-backend layout as `shake256/`.
2. Extend `luxcpp/gpu/include/lux/gpu.h` with the four batch APIs:
`lux_gpu_slhdsa_wotsplus_chain_batch`,
`lux_gpu_slhdsa_fors_subtree_batch`,
`lux_gpu_slhdsa_xmss_subtree_batch`,
`lux_gpu_slhdsa_hmsg_prfmsg_batch`.
3. Wire the GPU plugin into the magnetar `slhSignAtom` path via a
pluggable interface (the `prfOut` callback already is the
pluggability seam; one additional seam for the public-byte
hash batch is sufficient).
#### Expected throughput
Conservative estimate based on FIPS 205-SHAKE-192s shape (~50K
SHAKE256 calls per signature, ~12K per verify):
- CPU single-core sign: ~80ms (M1 Max)
- CPU single-core verify: ~2ms
- GPU batch sign (M=64, M1 Max Metal): ~5ms / signature
(~16x throughput at batch size 64)
- GPU batch verify (M=256, NVIDIA H100): ~0.05ms / verify
(~40x throughput at batch size 256)
The threshold for GPU dispatch matches the existing crypto/slhdsa
pattern: above `BatchVerifyThreshold ≈ 64`, GPU wins.
### 3.4 Honest scope: when GPU is unnecessary
For consensus-rate signing (~1 sig/block on the canonical Lux
consensus cadence), the CPU path is more than sufficient. The
GPU port is for the throughput consumers:
- High-throughput bridge custody signing (institutional bridge
validators processing many messages per second).
- N=100+ aggregate-cert verification.
- Backfilling slashing-evidence sweep across historical blocks.
The per-validator standalone primitive's typical deployment
(N = 21 validators producing one signature per block each) does
NOT need GPU acceleration to meet block-time bounds.
---
## 4. Magnetar canonical-name positioning across `luxfi/*`
### 4.1 Verified canonical surfaces
| Repo | Path | Magnetar role |
|---|---|---|
| `luxfi/magnetar` | `ref/go/pkg/magnetar/` | Reference implementation: PerValidatorKeypair + THBS-SE + strict-atom Combine + dealerless PVSS-DKG + slhdsa-internal §5-§8 walk |
| `luxfi/threshold` | `protocols/slhdsa-tee/` | TEE-attested signer + t-of-n CombinerPool for strict-PQ profile |
| `luxfi/threshold` | `pkg/thresholdd/magnetar.go` | JSON-RPC dispatcher; profile gate `magnetarRefuseUnderStrictPQ`; Sign / Sign_Ctx / Sign_TEE / Combine_TEE |
| `luxfi/threshold` | `study/magnetar.md` | Design study cross-referenced from Pulsar / Corona / cross-family-defense |
| `luxfi/precompile` | `magnetar/contract.go` | EVM precompile slot `0x012207` (LP-4200 canonical); FIPS 205 mode dispatch + per-mode gas |
| `luxfi/consensus` | `pkg/wire/zap/magnetar_aggregate.go` | LP-182 schema 0x04 wire view of `ValidatorAggregateCert`; embedded in Polaris-profile Magnetar leg |
| `luxfi/consensus` | `protocol/quasar/*.go` | References Magnetar as the per-validator-aggregate cert layer alongside ML-DSA / Pulsar |
| `luxfi/bridge` | `internal/mchain/protocol.go` + `cmd/bridge/signing_driver.go` | Bridge consumer of Magnetar signatures (M-Chain MPC custody primitive) |
| `luxfi/lux/crypto/slhdsa/` | `gpu.go`, `gpu_sign_test.go`, `gpu_test.go`, `provenance_test.go` | Tagged as "canonical Magnetar profile" in commentary; `CanonicalMagnetar = ModeSHA2_192f` in `crypto/pq/slhdsa/gpu/params.go` |
**No conflicting or legacy "SLH-DSA threshold" name exists.**
"Magnetar" is the single canonical name for the SLH-DSA threshold
construction across the entire `luxfi/*` ecosystem.
### 4.2 SHAKE-vs-SHA2 reconciliation
A subtle discrepancy: `luxfi/crypto/pq/slhdsa/gpu/params.go`
declares `CanonicalMagnetar = ModeSHA2_192f` (SHA2 family), while
the magnetar reference at `ref/go/pkg/magnetar/params.go` ships
ONLY the SHAKE family (M192s / M192f / M256s). Both are FIPS 205
compliant; the dual coverage is intentional --- the recovery-path
profile uses SHA2 (mirrors the EVM precompile's SHA2 modes), and
the threshold reference path uses SHAKE (because the
strict-atom-assembly `slhdsa_internal.go` implements the SHAKE
hash family only).
The precompile at `luxfi/precompile/magnetar/contract.go` handles
BOTH families correctly (`getModeParams` dispatches across all 12
modes). The headline canonical Magnetar parameter set in
production is SHAKE-192s (matching the v1.0 dispatcher default
`magnetar.MustParamsFor(magnetar.ModeM192s)`).
**Recommendation (informational, no code change required).**
`CanonicalMagnetar` in `luxfi/crypto/pq/slhdsa/gpu/params.go`
should evolve to a per-deployment knob rather than a single
constant. Today it pins the recovery-path profile, which is
correct for that consumer; the dispatcher's default `M192s` is
the canonical Magnetar production profile. The two values are
distinct deployments, not conflicting names.
### 4.3 SLH-DSA precompile (LP-4200 0x012203) vs Magnetar (0x012207)
LP-4200 reserves both slots:
- `0x012203 = SLH-DSA` (hash-based single-party signature)
- `0x012207 = Magnetar` (hash-based threshold FIPS 205)
The verifier is interchangeable (FIPS 205 byte-equal), but the
slot separation enables:
1. Gas-tier separation (threshold-emitted sigs may be metered
distinctly from single-party sigs);
2. Telemetry separation (on-chain accounting can attribute
Magnetar verifies separately);
3. Forward-compat (Magnetar could add non-FIPS-205 paths e.g.
identifiable-abort hints).
This is correctly decomplected per the user mandate. No legacy
aliases exist.
---
## 5. Open items
### 5.1 MAGNETAR-EXTERNAL-AUDIT-V13
External cryptographer review of:
1. THBS-SE construction shape (`thbsse.go` + `thbsse_field.go`);
2. Strict-atom-assembly path (`thbsse_assemble.go` +
`slhdsa_internal.go`);
3. Leaderless PVSS-DKG (`pvss_dkg.go`).
v0.x internal sign-off covered the abandoned v0.x surface, much
of which has been removed. v1.0 internal sign-off covers the
shipped surface up to the v1.0 line; v1.1 + v1.2 land additive
discipline (strict-atom + PVSS-DKG) without breaking the v1.0
wire format.
Status: OPEN.
### 5.2 MAGNETAR-GPU-PORT-V13
Land the four kernels described in §3.3 at
`lux-private/gpu-kernels/ops/crypto/slhdsa/` and wire through
`luxcpp/gpu` to the magnetar `slhSignAtom` substrate.
Status: PROPOSED (this audit).
### 5.3 MAGNETAR-APPLE-SE-HSM-V14
`hsm.Provider` backed by Apple Keychain with SecureEnclave-only
access control. Tests can mock; production Apple Silicon hosts
get a first-class HSM substrate.
Status: PROPOSED (this audit).
### 5.4 MAGNETAR-PROACTIVE-RESHARE-V13
Zero-secret-refresh against the same group public key. Lifts
the static-corruption bound to a refresh-window-bounded
adaptive-corruption bound. Forward-compatible share envelope
shape; no wire break.
Status: PROPOSED (this audit).
---
## 6. Verification
```bash
cd /Users/z/work/lux/magnetar/ref/go && \
GOWORK=off go build ./... && \
GOWORK=off go vet ./... && \
GOWORK=off go test -count=1 -short -timeout 600s ./pkg/magnetar/...
```
All clean as of 2026-06-03 audit:
- `go build ./...` --- OK
- `go vet ./...` --- OK
- `go test -count=1 -short ./pkg/magnetar/...` --- ok 192.033s
```bash
cd /Users/z/work/lux/magnetar && bash scripts/checks/strict-atom-ast.sh
```
`strict-atom-ast: GATE GREEN` --- the four-pattern audit grep
returns zero matches and `TestThbsSE_StrictAtom_NoTransientSeed`
passes.
```bash
cd /Users/z/work/lux/threshold && \
GOWORK=off go test -count=1 -short ./pkg/thresholdd/ \
-run 'TestMagnetar' -timeout 600s
```
Magnetar dispatcher tests pinned in `magnetar_tee_gate_test.go`.
---
## 7. Recommendation
**APPROVED for v1.2 production deployment** on Lux
public-permissionless chains under the documented threat model.
- Per-validator standalone: APPROVED for unconditional production
use (legacy-compat AND strict-PQ chains --- each validator's
standalone keypair is fully attested at the consensus layer's
validator registry).
- THBS-SE under legacy-compat profile: APPROVED for production
use; combiner role is public; the residual microsecond residency
window of master bytes in the public combiner's
`derivedMaterial` is honestly documented in `SECURITY.md` §7.2.
- THBS-SE under strict-PQ profile: APPROVED via the sibling
`luxfi/threshold/protocols/slhdsa-tee` package's t-of-n
attested-combiner pool with AMD SEV-SNP attestation.
Track the four open items above against v1.3 / v1.4 milestones.
The shipped v1.2 architecture is forward-compatible with all four
lifts.
---
**Document metadata**
- Name: `AUDIT-2026-06.md`
- Reviewer: cryptographer agent (internal review)
- Date: 2026-06-03
- Magnetar reviewed at commit: `d640d15`
+50
View File
@@ -227,6 +227,53 @@ external audit should target the THBS-SE construction shape, the
strict-atom-assembly path, and the leaderless PVSS-DKG setup, all strict-atom-assembly path, and the leaderless PVSS-DKG setup, all
of which land at v1.1. of which land at v1.1.
## v1.3 / v1.4 work items (proposed 2026-06-03 audit)
### MAGNETAR-GPU-PORT-V13 --- Batched FIPS 205 hash-tree GPU kernels
**Status:** PROPOSED. Scope: v1.3.
Land four batched SHAKE256-based kernels at
`lux-private/gpu-kernels/ops/crypto/slhdsa/` and wire through
`luxcpp/gpu` to the magnetar `slhSignAtom` substrate. Kernels:
- `magnetar_wotsplus_chain_batch` --- FIPS 205 §5 chain
(CPU `wotsChain`).
- `magnetar_fors_subtree_batch` --- FIPS 205 §8.2 FORS subtree
(CPU `forsNodeCompute`).
- `magnetar_xmss_subtree_batch` --- FIPS 205 §6.1 XMSS subtree
(CPU `xmssNodeCompute`).
- `magnetar_hmsg_prfmsg_batch` --- FIPS 205 §11.2 SHAKE H_msg /
PRF_msg (CPU `hMsgPub` and `prfMsg` callback).
Full design + throughput estimates + 5-backend file layout
in `GPU-PORT-PLAN.md`.
Consumers: high-throughput bridge custody signing, N=100+
aggregate-cert verification, slashing-evidence sweep across
historical blocks. NOT required for consensus-rate signing
(~1 sig/block CPU-bound on commodity hardware is sufficient).
### MAGNETAR-PROACTIVE-RESHARE-V13 --- Zero-secret refresh
**Status:** PROPOSED. Scope: v1.3.
Augment the PVSS-DKG with proactive resharing against the same
group public key. Lifts the static-corruption bound to a
refresh-window-bounded adaptive-corruption bound. Share envelope
shape is forward-compatible; no wire break.
### MAGNETAR-APPLE-SE-HSM-V14 --- Apple Keychain SE-only hsm.Provider
**Status:** PROPOSED. Scope: v1.4.
`hsm.Provider` implementation backed by Apple Keychain with
`kSecAttrAccessControl = kSecAccessControlSecureEnclaveOnly`.
Tests can mock; production Apple Silicon hosts get a first-class
HSM substrate that layers BELOW the attestation chain (the
Apple SE is NOT a substitute for SEV-SNP / TDX / NRAS
attestation, it is the at-rest seed wrap).
## Cross-references ## Cross-references
- v1.0 construction spec: `THBS-SPEC.md` - v1.0 construction spec: `THBS-SPEC.md`
@@ -234,3 +281,6 @@ of which land at v1.1.
- v1.0 proof track: `proofs/README.md` - v1.0 proof track: `proofs/README.md`
- v1.0 CT track: `ct/README.md` - v1.0 CT track: `ct/README.md`
- v1.0 release notes: `CHANGELOG.md` v1.0.0 entry - v1.0 release notes: `CHANGELOG.md` v1.0.0 entry
- v1.2 audit: `AUDIT-2026-06.md`
- v1.3 TEE integration spec: `TEE-INTEGRATION.md`
- v1.3 GPU port plan: `GPU-PORT-PLAN.md`
+450
View File
@@ -0,0 +1,450 @@
# Magnetar --- GPU acceleration port plan
This document scopes the v1.3 GPU-acceleration work item:
landing four batched FIPS 205 SLH-DSA hash-tree kernels at
`lux-private/gpu-kernels/ops/crypto/slhdsa/` and wiring them
through `luxcpp/gpu` into the magnetar `slhSignAtom` substrate.
> **Why this isn't already done.** The shipped magnetar
> implementation (`ref/go/pkg/magnetar/slhdsa_internal.go`) walks
> FIPS 205 §5-§8 sequentially in pure Go. For consensus-rate
> signing (1 sig/block) this is sufficient on commodity CPU. The
> GPU path is for throughput consumers: bridge custody, N=100+
> aggregate-cert verification, slashing-evidence sweep across
> historical blocks.
---
## 1. The substrate that already exists
`lux-private/gpu-kernels/ops/crypto/` already ships:
| Op | Backends | Purpose for Magnetar |
|---|---|---|
| `shake256/` | CUDA + HIP + Metal + Vulkan + WGSL | FIPS 202 XOF; every SLH-DSA hash call goes through here |
| `sha3_256/` | CUDA + HIP + Metal + Vulkan + WGSL | Same Keccak-f[1600] permutation, different domain separator |
| `keccak256/` | CUDA + HIP + Metal + Vulkan + WGSL | Same permutation, Ethereum padding |
Permission to share `keccak_f1600.cuh` is documented in the
`shake256/op.yaml` notes block:
> Shares the same Keccak-f[1600] permutation as keccak256 /
> sha3_256 / cshake256. The CUDA / HIP TUs pull in
> `../keccak256/keccak_f1600.cuh` for one source of truth on the
> permutation; Vulkan + WGSL embed identical f1600 bodies in
> their respective shaders (GLSL/WGSL have no shared-include
> mechanism that survives the per-backend shader staging step).
The four magnetar kernels below sit on top of `shake256` and add
NO new permutation code --- they are FIPS 205-shape composition
of existing SHAKE256 absorbs.
---
## 2. Kernel 1: `magnetar_wotsplus_chain_batch`
### Signature
```
status = lux_gpu_magnetar_wotsplus_chain_batch(
const lux_magnetar_wots_chain_input* in, // batch of input tuples
lux_magnetar_wots_chain_output* out, // batch of output bytes
size_t batch_size // M (>= 1)
);
struct lux_magnetar_wots_chain_input {
const uint8_t* pk_seed; // n bytes (n = 24 for M192s, 32 for M256s)
uint8_t addr[32]; // FIPS 205 §4.2 address (32 bytes for SHAKE)
const uint8_t* x_base; // n bytes (the chain base)
uint32_t i; // starting hash address
uint32_t s; // chain length (0..15 for w=16)
};
struct lux_magnetar_wots_chain_output {
uint8_t out[32]; // n bytes (24 for M192s, 32 for M256s); upper bytes zero
};
```
### Semantics
For each batch element `(pk_seed, addr, x_base, i, s)`:
```
tmp ← x_base
for j ∈ [i, i+s):
addr.setHashAddress(j) // mutate bytes [28:32] of addr
tmp ← SHAKE256(pk_seed || addr || tmp)[:n]
out ← tmp
```
This is FIPS 205 §5 Algorithm 5 `chain`, executed independently
for each batch element.
### Parallelism
- **Across batch elements**: trivial, one CUDA thread / Metal
thread / Vulkan workgroup per element.
- **Within one element**: NONE (chain is sequential by
construction).
### Use sites in `ref/go/pkg/magnetar/slhdsa_internal.go`
- `wotsChain` line 402 — invoked inside `wotsSign:442` and
`wotsPkFromSig:645`.
- `wotsSign` line 442 — `wotsLen = 2n + 3` chain computations per
WOTS+ signature.
- `wotsPkGen` line 499 — same.
- `wotsPkFromSig` line 645 — used in `xmssPkFromSig:607`,
which is invoked `d-1` times during hypertree sign (verify-side
recomputation for the chained-root case).
### Volume per signature (M192s shape: n=24, d=7, hPrime=9, wotsLen=51)
- One hypertree sign: `d × 2^hPrime × wotsLen` chain computations
for full PK gen at one layer (only at layer 0, the leaves):
`1 × 512 × 51 = 26,112` chains.
- WOTS+ sign per leaf: `wotsLen = 51` chains.
- Total per signature: ~26,000-30,000 chains. At GPU throughput of
~10⁷ chains/sec on H100 → ~3ms per signature for the
WOTS+ kernel alone.
---
## 3. Kernel 2: `magnetar_fors_subtree_batch`
### Signature
```
status = lux_gpu_magnetar_fors_subtree_batch(
const lux_magnetar_fors_subtree_input* in,
lux_magnetar_fors_subtree_output* out,
size_t batch_size
);
struct lux_magnetar_fors_subtree_input {
const uint8_t* pk_seed; // n bytes
uint8_t addr[32]; // FIPS 205 §4.2 address
uint32_t leaf_idx; // FORS subtree leaf index
uint32_t height; // FORS subtree height to compute
// The secret-derived FORS seed is provided host-side via
// the prfOut callback; per-element callers pre-populate the
// sk_leaves array with the PRF outputs for the relevant
// leaves.
const uint8_t* sk_leaves; // (2^height) × n bytes
};
struct lux_magnetar_fors_subtree_output {
uint8_t out[32]; // n bytes (the subtree node value)
};
```
### Semantics
For each batch element, compute the FORS subtree node at
`(leaf_idx, height)` using `F(pk_seed, addr, sk_leaf_i)` at the
leaves and `H(pk_seed, addr, left || right)` at internal nodes.
FIPS 205 §8.2 Algorithm 15.
### Parallelism
- **Across batch elements**: one thread block per element.
- **Within one element**: across the `2^height` leaves and the
pairwise reductions at each height level (binary-tree
reduction).
### Use sites
- `forsNodeCompute` line 735.
- `forsSign` line 780 — `k` subtrees per signature; for M192s,
`k=17` subtrees of height `a=14`.
### Volume per signature (M192s shape)
- `k × (2^a - 1) = 17 × 16383 = ~280K` SHAKE absorbs.
- Plus the secret-derived `sk_leaf` computations: `k × 2^a =
~278K` PRF callbacks (handled on the host inside the
strict-atom callback).
---
## 4. Kernel 3: `magnetar_xmss_subtree_batch`
### Signature
```
status = lux_gpu_magnetar_xmss_subtree_batch(
const lux_magnetar_xmss_subtree_input* in,
lux_magnetar_xmss_subtree_output* out,
size_t batch_size
);
struct lux_magnetar_xmss_subtree_input {
const uint8_t* pk_seed; // n bytes
uint8_t addr[32];
uint32_t leaf_idx;
uint32_t height;
// Host pre-populates the WOTS+ public-key values at the
// leaves of this subtree.
const uint8_t* wots_pk_leaves; // (2^height) × n bytes
};
struct lux_magnetar_xmss_subtree_output {
uint8_t out[32]; // n bytes (the subtree node value)
};
```
### Semantics
For each batch element, compute the XMSS subtree node at
`(leaf_idx, height)` using `H(pk_seed, addr, left || right)`
internal nodes. FIPS 205 §6.1 Algorithm 9.
The WOTS+ leaf computation is delegated to kernel 1; this kernel
takes the resulting leaf bytes as input and performs the
pairwise hash reductions.
### Parallelism
- **Across batch elements**: one thread block per element.
- **Within one element**: binary-tree reduction.
### Use sites
- `xmssNodeCompute` line 546.
- `xmssSign` line 582 — auth-path computation (`hPrime` sibling
nodes per XMSS layer).
- `xmssPkFromSig` line 607 — verifier-side recomputation.
### Volume per signature (M192s shape: hPrime=9, d=7)
- Per XMSS sign: `hPrime` auth-path nodes; each requires a
subtree node at some height. Total: ~256 SHAKE absorbs per
XMSS sign.
- Per hypertree sign: `d × xmss_sign_cost` = `7 × ~256 = ~1,800`
SHAKE absorbs.
---
## 5. Kernel 4: `magnetar_hmsg_prfmsg_batch`
### Signature
```
status = lux_gpu_magnetar_hmsg_prfmsg_batch(
const lux_magnetar_hmsg_input* hmsg_in, // batch of H_msg inputs
lux_magnetar_hmsg_output* hmsg_out,
const lux_magnetar_prfmsg_input* prfmsg_in, // batch of PRF_msg inputs
lux_magnetar_prfmsg_output* prfmsg_out,
size_t hmsg_batch,
size_t prfmsg_batch
);
struct lux_magnetar_hmsg_input {
const uint8_t* r; // n bytes
const uint8_t* pk_seed; // n bytes
const uint8_t* pk_root; // n bytes
const uint8_t* msg_prime;
size_t msg_prime_len;
};
struct lux_magnetar_hmsg_output {
uint8_t digest[64]; // m bytes (39 for M192s, 42 for M192f, 47 for M256s)
};
struct lux_magnetar_prfmsg_input {
const uint8_t* sk_prf_segment; // n bytes; provided by host via strict-atom callback
const uint8_t* opt_rand; // n bytes
const uint8_t* msg_prime;
size_t msg_prime_len;
};
struct lux_magnetar_prfmsg_output {
uint8_t out[32]; // n bytes
};
```
### Semantics
`H_msg(R, PK.seed, PK.root, M')` and `PRF_msg(SK.prf, optRand,
M')` per FIPS 205 §11.2 SHAKE instantiation. Both are single
SHAKE256 absorb-and-squeeze calls.
### Parallelism
Trivial across batch elements.
### Use sites
- `hMsgPub` line 341 — exactly one per signature.
- `prfMsg` callback — exactly one per signature.
### Volume per signature
2 SHAKE absorbs (one per kernel). These exist as a separate
kernel only because batching them across many independent
signatures amortizes the kernel launch overhead.
---
## 6. File layout
```
lux-private/gpu-kernels/
└── ops/
└── crypto/
└── slhdsa/ # NEW
├── op.yaml # op metadata; 5 backends
├── cuda.cu # 4 kernels in one TU
├── hip.cu # mirror, __HIPCC__-gated
├── metal.metal # MSL source
├── vulkan/ # GLSL sources
│ ├── wotsplus_chain.comp
│ ├── fors_subtree.comp
│ ├── xmss_subtree.comp
│ └── hmsg_prfmsg.comp
└── wgsl/ # WGSL sources
├── wotsplus_chain.wgsl
├── fors_subtree.wgsl
├── xmss_subtree.wgsl
└── hmsg_prfmsg.wgsl
```
Plus the C ABI extension at
`luxcpp/gpu/include/lux/gpu.h`:
```
// SLH-DSA hash-tree batched primitives. See ops/crypto/slhdsa/op.yaml.
int lux_gpu_magnetar_wotsplus_chain_batch(
const lux_magnetar_wots_chain_input* in,
lux_magnetar_wots_chain_output* out,
size_t batch_size);
int lux_gpu_magnetar_fors_subtree_batch(/* ... */);
int lux_gpu_magnetar_xmss_subtree_batch(/* ... */);
int lux_gpu_magnetar_hmsg_prfmsg_batch(/* ... */);
```
Plus the backend plugin ABI extension at
`luxcpp/gpu/include/lux/gpu/backend_plugin.h` (v9 bump):
```
typedef int (*op_magnetar_wotsplus_chain_batch_fn)(/* same shape */);
// Three more.
```
CPU backend reference implementation at
`luxcpp/gpu/src/cpu_backend.cpp::cpu_op_magnetar_wotsplus_chain_batch`
mirrors `wotsChain` in `slhdsa_internal.go` --- per-element
sequential, no parallelism inside the chain --- so CPU oracle is
the reference for byte-identity tests.
---
## 7. Go-side wiring
The pluggability seam in magnetar is the existing `prfOut`
callback (`slhdsa_internal.go:286`). For the GPU acceleration
path we add ONE additional seam: a `publicHashBatch` interface
that the four hash-tree primitives dispatch to when available.
```go
// PublicHashBatch is the optional batched-SHAKE substrate.
// Implementations include luxcpp/gpu via cgo bindings.
// The strict-atom Combine path holds a PublicHashBatch reference
// and dispatches to it for the four kernels above when the
// batch size exceeds the dispatch threshold.
type PublicHashBatch interface {
WotsPlusChainBatch(in []WotsChainInput, out []WotsChainOutput) error
ForsSubtreeBatch(in []ForsSubtreeInput, out []ForsSubtreeOutput) error
XmssSubtreeBatch(in []XmssSubtreeInput, out []XmssSubtreeOutput) error
HMsgPrfMsgBatch(hmsgIn []HMsgInput, hmsgOut []HMsgOutput,
prfMsgIn []PrfMsgInput, prfMsgOut []PrfMsgOutput) error
}
```
Wiring at `assembleSignatureBytes` and `ValidatorBatchVerify` is
the same shape `luxfi/crypto/slhdsa/gpu.go` already uses for the
existing `luxfi/accel`-based path: detect the substrate via
`accel.Available()`, route batches above the threshold to GPU,
fall back to CPU for small batches.
---
## 8. Expected throughput
Conservative estimates (numbers grounded in the existing
`luxfi/crypto/slhdsa` GPU benches and the published `shake256`
kernel performance on Apple M1 Max + NVIDIA H100):
| Op | CPU 1-core (M1 Max) | GPU M1 Max Metal (batch 64) | GPU H100 (batch 256) |
|---|---|---|---|
| SLH-DSA-SHAKE-192s sign | ~80 ms | ~5 ms (16x) | ~0.6 ms (130x) |
| SLH-DSA-SHAKE-192s verify | ~2 ms | ~0.15 ms (13x) | ~0.05 ms (40x) |
### Threshold for GPU dispatch
Matches the existing
`crypto/slhdsa.LastValidatorBatchTier` pattern:
| Tier | Batch size | Backend |
|---|---|---|
| Serial | 1..63 | CPU single-core |
| Concurrent | 64..511 | CPU goroutine-parallel |
| GPU | 512+ | luxcpp/gpu (if Available) |
The break-even at 512 reflects the kernel-launch overhead on
discrete GPUs; on Apple Silicon UMA the break-even is lower
(~64 elements).
---
## 9. Verification + tests
Each kernel is byte-identity tested against the CPU oracle (which
is the existing `slhdsa_internal.go` walk):
```
ops/crypto/slhdsa/tests/
├── test_magnetar_wotsplus_chain_kat.cpp # NIST FIPS 205 KAT
├── test_magnetar_fors_subtree_kat.cpp
├── test_magnetar_xmss_subtree_kat.cpp
└── test_magnetar_hmsg_prfmsg_kat.cpp
```
Each test:
1. Runs the CPU oracle on a fixed input batch.
2. Runs the active GPU plugin on the same batch.
3. Byte-compares outputs.
The vector source is FIPS 205 Algorithm 22 (slh_sign) intermediate
states, captured from `cloudflare/circl/sign/slhdsa` at the four
seams. Vectors live at
`lux-private/gpu-kernels/ops/crypto/slhdsa/vectors/`.
---
## 10. v1.3 work-item summary
| Task | Estimate | Owner |
|---|---|---|
| Land 4 CUDA kernels + tests | 5 days | tbd |
| Land 4 HIP kernels (port from CUDA via macro gating) | 1 day | tbd |
| Land 4 Metal kernels + KAT | 4 days | tbd |
| Land 4 Vulkan GLSL kernels + KAT | 4 days | tbd |
| Land 4 WGSL kernels + KAT | 3 days | tbd |
| `luxcpp/gpu` C ABI + plugin ABI extension (v8 → v9) | 2 days | tbd |
| CPU oracle in `luxcpp/gpu/src/cpu_backend.cpp` | 2 days | tbd |
| Magnetar Go-side `PublicHashBatch` interface + wiring | 3 days | tbd |
| `luxfi/crypto/slhdsa/gpu.go` dispatch update | 1 day | tbd |
| Bench suite + leaderboard cells | 2 days | tbd |
| **Total** | **~27 days** | |
Status: PROPOSED. Not v1.2-blocking.
---
**Document metadata**
- Name: `GPU-PORT-PLAN.md`
- Date: 2026-06-03
- Tracks: `BLOCKERS.md::MAGNETAR-GPU-PORT-V13`
+10
View File
@@ -225,6 +225,16 @@ M-LWE + Corona R-LWE) with hash-based PQ (Magnetar SLH-DSA).
- `LICENSING.md` --- license terms. - `LICENSING.md` --- license terms.
- `SUBMISSION.md` / `NIST-SUBMISSION.md` / `SUBMISSION-STATUS.md` --- - `SUBMISSION.md` / `NIST-SUBMISSION.md` / `SUBMISSION-STATUS.md` ---
NIST MPTC submission framework. NIST MPTC submission framework.
- `AUDIT-2026-06.md` --- 2026-06 production-readiness audit
(public-permissionless-chain safety, TEE integration story,
GPU acceleration story, canonical-name positioning).
- `TEE-INTEGRATION.md` --- TEE-attested production surface spec
(SEV-SNP today, TDX + NRAS post-#222, operator-side wiring).
- `GPU-PORT-PLAN.md` --- v1.3 GPU acceleration port plan (four
batched FIPS 205 hash-tree kernels at
`lux-private/gpu-kernels/ops/crypto/slhdsa/`).
- `SECURITY.md` --- threat model + strict-PQ profile closure.
- `ASSEMBLE-INVARIANT.md` --- strict-atom Combine invariant.
## Build ## Build
+383
View File
@@ -0,0 +1,383 @@
# Magnetar --- TEE integration specification
This document is the canonical design + integration story for
Magnetar's TEE-attested production surface. It is the load-bearing
prose for the `strict-PQ` chain profile at deployment time.
> **Decomplecting discipline.** The TEE integration is the
> SIBLING package at `luxfi/threshold/protocols/slhdsa-tee` ---
> NOT a new field on the magnetar primitive. Magnetar stays the
> hash-tree arithmetic; slhdsa-tee composes the trust root +
> attestation + HSM + approval flow. The two compose by function
> composition, not by inheritance.
---
## 1. Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ Caller (RPC / EVM precompile) │
└──────────────┬──────────────────────────────────┬───────────┘
│ Sign / Sign_Ctx │ Sign_TEE / Combine_TEE
│ (legacy-compat) │ (strict-PQ)
▼ ▼
┌───────────────────────┐ ┌──────────────────────────────────┐
│ magnetar.ValidatorSign│ │ slhdsa-tee.Signer.Sign │
│ (per-validator) │ │ • approval.ApproveIntent │
└───────────────────────┘ │ • gate.Issue (nonce+epoch) │
│ • gate.Release (attest+RIM) │
┌───────────────────────┐ │ • hsm.Provider.GetKey │
│ magnetar.Combine │ │ • magnetar.Sign (inside TEE) │
│ (strict-atom Combine)│ │ • zeroize on return │
│ (THBS-SE public) │ └──────────────────────────────────┘
└───────────────────────┘ │
┌──────────────────────────────────┐
│ slhdsa-tee.CombinerPool.Combine │
│ • snapshot members under RLock │
│ • freshness gate (RotationWindow)│
│ • drive each member's Sign │
│ • byte-equality across quorum │
│ • refuse divergence │
└──────────────────────────────────┘
┌──────────────────────────────────┐
│ cc/attest/{sev,tdx,nras}.go │
│ • SEV-SNP: PRODUCTION │
│ • TDX: STUB (#222 stage 2) │
│ • NRAS: STUB (#222 stage 3) │
└──────────────────────────────────┘
```
---
## 2. Component contracts
### 2.1 Magnetar (this repo)
- **Lane**: FIPS 205 hash-tree arithmetic (FORS, WOTS+, XMSS,
hypertree). Pure functions.
- **Inputs (sign path)**: `Params, *PrivateKey, msg, ctx,
randomized, rng`.
- **Output**: `Signature` (FIPS 205 wire bytes).
- **No knowledge of**: TEE, HSM, approval, gate, attestation.
Pure crypto.
### 2.2 slhdsa-tee.Signer (sibling, `luxfi/threshold/protocols/slhdsa-tee`)
- **Lane**: institutional-custody composition. The full
attested-release flow that ends in a magnetar.Sign call.
- **Inputs**: `Envelope (attestation, RIM, hardware, TEEPub),
jobID, msg, signCtx`.
- **Output**: `(wireBytes, *SignReceipt, error)`.
- **Composes**: `kms.ReleaseGate + hsm.Provider +
approval.ApprovalProvider + Config`.
- **Does NOT compose** magnetar itself --- the Signer holds an
`hsm.Provider` reference and unwraps the master seed inside the
TEE, then calls `magnetar.KeyFromSeed + magnetar.Sign` on the
unwrapped seed.
### 2.3 slhdsa-tee.CombinerPool (sibling)
- **Lane**: t-of-n attested-combiner agreement. The strict-PQ
Sign surface.
- **Inputs**: `map[memberName]*Envelope, jobID, msg, signCtx`.
- **Output**: `(wireBytes, []*SignReceipt, error)` --- one
consolidated wire signature byte-equal across the quorum, plus
per-member audit signatures.
- **Composes**: N `*slhdsa-tee.Signer` instances (one per attested
host) + freshness state (`LastIssuedAt` per member).
- **Refusal sentinels**: `ErrMagnetarNoTEEAttestation`,
`ErrMagnetarStaleAttestation`, `ErrMagnetarInsufficientQuorum`,
`ErrMagnetarSignatureDivergence`.
### 2.4 cc/attest (sibling, `luxfi/mpc/cc/attest`)
- **Lane**: vendor evidence chain validation. Maps from
vendor-framed quote bytes to `VerifiedReport`
(Vendor + IssuedAt + ReportData).
- **Status**: SEV-SNP PRODUCTION; TDX + NRAS STUB.
### 2.5 hsm.Provider (sibling, `luxfi/mpc/pkg/hsm`)
- **Lane**: at-rest seed wrap. Implementations include file
(dev), AWS KMS, Azure Key Vault, GCP Cloud KMS.
- **Inputs**: `keyID, ctx`.
- **Output**: wrapped (or AEAD-sealed) bytes.
### 2.6 kms.ReleaseGate (sibling, `luxfi/mpc/pkg/kms`)
- **Lane**: fresh-nonce + policy-bound release decision.
- **Issue**: returns `(nonce, epoch)` for a job; must be presented
in the subsequent Release call.
- **Release**: takes `ReleaseRequest{JobID, Epoch, Nonce,
Attestation, Ctx}` and returns a `SealedSessionKey` if
policy + attestation pass.
### 2.7 approval.ApprovalProvider (sibling, `luxfi/mpc/pkg/approval`)
- **Lane**: out-of-band human / programmatic approval of a sign
intent. Used when `Config.ApprovalRequired = true`.
- **Inputs**: `SignIntent` (jobID, msg, env-bound).
- **Output**: `ApprovalSignature`.
---
## 3. Profile gate (one function, one place)
The profile gate is **the only** decomplecting point between the
permissionless and strict-PQ paths. The function is
`magnetarRefuseUnderStrictPQ` at
`luxfi/threshold/pkg/thresholdd/magnetar.go:242`. It mirrors:
- `RefuseUnderStrictPQ` at
`luxfi/precompile/contract/strict_pq.go` (precompile-side gate
consulted at the top of every classical precompile's `Run`).
- `RefuseUnderStrictPQ` at `luxfi/threshold/pkg/thresholdd/
profile.go` (per-request chain-ID resolver gate for HTTP
503 mapping).
### Discipline
1. **ONE function**. No duplication across schemes (every PQ
primitive that has a strict-PQ-only path consults its own gate
function with this exact shape).
2. **ONE place**. Called at the top of `Sign` and `Sign_Ctx` ---
the permissionless paths. Never called from `Sign_TEE` /
`Combine_TEE` (which are the strict-PQ-permitted paths).
3. **ONE canonical refusal sentinel**.
`slhdsatee.ErrMagnetarNoTEEAttestation` with wire identifier
`ERR_MAGNETAR_NO_TEE_ATTESTATION`.
### Cascade on chain profile flip
Operators rotating a chain into strict-PQ MUST follow:
1. Flip the chain profile in `luxfi/node` ChainConfig.
2. Flip the magnetar dispatcher's profile via
`magnetarScheme.SetChainSecurityProfile(ProfileStrictPQ)`.
3. Wire a `CombinerPool` via `SetCombinerPool` with at least
`Threshold` attested members already provisioned.
Until all three steps complete, the dispatcher fail-closes:
`Sign` / `Sign_Ctx` refuse; `Combine_TEE` refuses with
`errMagnetarPoolUnwired`. No silent fallback.
---
## 4. Production deployment matrix
| Chain profile | Sign primitive | TEE substrate | KnownIssuers map |
|---|---|---|---|
| `legacy-compat` (default) | per-validator standalone | none | --- |
| `legacy-compat` (THBS-SE) | public combiner | none | --- |
| `legacy-compat` (custody opt-in) | `Combine_TEE` (1-of-1) | SEV-SNP | `{"amd.sev.snp": {}}` |
| `strict-PQ` (production today) | `Combine_TEE` (t-of-n) | SEV-SNP | `{"amd.sev.snp": {}}` |
| `strict-PQ` (post-#222 stage 2) | `Combine_TEE` (t-of-n) | SEV-SNP + TDX | `{"amd.sev.snp": {}, "intel.tdx": {}}` |
| `strict-PQ` (post-#222 stage 3) | `Combine_TEE` (t-of-n) | + NVIDIA NRAS | `{"amd.sev.snp": {}, "intel.tdx": {}, "nvidia.nras.v1": {}}` |
### 4.1 NVIDIA Confidential Computing (H100 / H200 / B200) integration
When `luxfi/mpc/cc/attest/nras.go` ships its production chain
validator (NVIDIA Remote Attestation Service, `nvtrust` SDK
integration), the operator's CombinerPool config adds
`"nvidia.nras.v1": {}` to KnownIssuers. Each attested member's
slhdsa-tee.Signer runs inside a NVIDIA Confidential Compute VM on
H100/H200/B200. The CC VM's measurement (firmware + UEFI + VBS +
TEE workload) is chain-validated against NRAS's JWKS. No
magnetar-side code change.
For the **deployment-time** Apple SE / Apple Silicon story, see
the v1.4 work item `MAGNETAR-APPLE-SE-HSM-V14` --- the Apple SE
is layered BELOW the attestation as the `hsm.Provider`, not as a
substitute for the attestation chain.
---
## 5. Wire compatibility
The TEE integration is **completely opaque to verifiers**. Any
party holding the canonical MAGG-framed group public key
validates a TEE-emitted signature via stock
`magnetar.VerifyBytes(gkBytes, msg, sigBytes)` --- no special
casing, no TEE-aware verifier, no extra round-trips.
This is the load-bearing property: the TEE substrate provides
custody discipline, NOT verification discipline. The on-chain
verifier (the EVM precompile at slot `0x012207`) does NOT know
or care whether the signature came from:
- a per-validator standalone keypair on a commodity host,
- a public combiner on a commodity host running THBS-SE,
- a 1-of-1 attested-host TEE,
- a t-of-n attested-combiner pool spanning SEV-SNP + TDX + NRAS.
All four paths emit byte-identical FIPS 205 wire bytes.
---
## 6. Stub Go integration code (operator-side reference)
The following is a minimal operator-side reference for wiring a
`strict-PQ` chain into the magnetar dispatcher with NVIDIA
Confidential Compute. It is NOT in this repo (the TEE primitives
live at `luxfi/threshold/protocols/slhdsa-tee`); reproduced here
for the spec's completeness.
```go
package main
import (
"context"
"time"
"github.com/luxfi/mpc/cc/attest"
"github.com/luxfi/mpc/pkg/approval"
"github.com/luxfi/mpc/pkg/hsm"
"github.com/luxfi/mpc/pkg/kms"
magnetar "github.com/luxfi/magnetar/ref/go/pkg/magnetar"
slhdsatee "github.com/luxfi/threshold/protocols/slhdsa-tee"
"github.com/luxfi/threshold/pkg/thresholdd"
)
// configureMagnetarStrictPQ wires a strict-PQ Magnetar dispatcher
// with a 2-of-3 attested-combiner pool across AMD SEV-SNP +
// NVIDIA NRAS. Called once at operator boot.
func configureMagnetarStrictPQ(
ctx context.Context,
dispatcher *thresholdd.MagnetarScheme,
gate kms.ReleaseGate,
hsmP hsm.Provider,
approver approval.ApprovalProvider,
) error {
// 1. Flip the dispatcher into strict-PQ. From this point on,
// Sign / Sign_Ctx refuse with ErrMagnetarNoTEEAttestation.
// Only Sign_TEE / Combine_TEE can produce signatures.
dispatcher.SetChainSecurityProfile(slhdsatee.ProfileStrictPQ)
// 2. Build the attested-combiner pool. KnownIssuers includes
// both AMD SEV-SNP (production today) AND NVIDIA NRAS
// (post-#222 stage 3).
pool, err := slhdsatee.NewCombinerPool(slhdsatee.CombinerPoolConfig{
Threshold: 2, // 2-of-3, no single-host quorum
RotationWindow: 60 * time.Second, // 60 blocks of slack
KnownIssuers: map[string]struct{}{
"amd.sev.snp": {},
"nvidia.nras.v1": {}, // assumes cc/attest/nras.go has shipped
},
})
if err != nil {
return err
}
// 3. Register the three attested signers. Each signer has its
// own wrapped seed in its own HSM key slot; the pool drives
// each member's full slhdsa-tee.Signer.Sign machinery.
for _, m := range []struct {
name string
keyID string
mode magnetar.Mode
}{
{name: "us-east-1a-snp-01", keyID: "magnetar/east/snp01", mode: magnetar.ModeM192s},
{name: "us-west-2b-snp-02", keyID: "magnetar/west/snp02", mode: magnetar.ModeM192s},
{name: "eu-central-1a-nras-01", keyID: "magnetar/eu/nras01", mode: magnetar.ModeM192s},
} {
signer, err := slhdsatee.New(gate, hsmP, approver, slhdsatee.Config{
Mode: m.mode,
WrappedSeedKeyID: m.keyID,
ApprovalRequired: true, // require human sign-off per call
ApproverID: "operator@example.com",
RequireSEV: false, // accept any KnownIssuer
RequireTDX: false,
RequireNRAS: false,
})
if err != nil {
return err
}
if _, err := pool.AddMember(m.name, signer); err != nil {
return err
}
}
// 4. Wire the pool into the dispatcher. From this point on,
// Combine_TEE drives the pool; Sign_TEE drives a single
// attested host.
dispatcher.SetCombinerPool(pool)
// 5. Initial attestation tick. Production deployments would
// re-attest every block (~1s); the 60s RotationWindow
// absorbs ~60 blocks of control-plane latency before any
// sign would refuse.
for _, name := range []string{
"us-east-1a-snp-01",
"us-west-2b-snp-02",
"eu-central-1a-nras-01",
} {
// The operator's control-plane captures fresh attestation
// evidence from the named TEE and submits it.
env := captureFreshAttestation(name) // operator-side hook
if err := pool.Attest(ctx, name, env); err != nil {
return err
}
}
return nil
}
// captureFreshAttestation is the operator's control-plane hook.
// For SEV-SNP: capture SNP_GUEST_REQUEST quote via the in-VM agent.
// For TDX: capture TDREPORT via the in-VM agent.
// For NRAS: capture NRAS-JWT via nvidia-attest agent + NRAS API.
// Each returns an *slhdsatee.Envelope wrapping the vendor quote.
func captureFreshAttestation(name string) *slhdsatee.Envelope {
// ... vendor-specific quote capture ...
return &slhdsatee.Envelope{
Kind: attest.Kind{
Vendor: "amd.sev.snp", // or "nvidia.nras.v1"
Format: "snp.v1", // or "nras.jwt.v1"
},
EvidenceBytes: nil, // populate from quote
RIM: [32]byte{}, // operator-asserted RIM digest
Hardware: [32]byte{}, // hardware fingerprint
TEEPub: [32]byte{}, // X25519 TEE pubkey
}
}
```
The above is the operator-side wiring; the magnetar reference
package itself stays pure.
---
## 7. Verification end-to-end
Pinned by `magnetar_tee_gate_test.go` in
`luxfi/threshold/pkg/thresholdd/`:
- `TestMagnetarCombine_StrictPQProfile_RequiresTEE` --- strict-PQ
refuses `Sign` and `Sign_Ctx`; permits `Combine_TEE` only when
pool is wired; profile flip is reversible + idempotent.
- `TestMagnetarCombine_AttestationVerified_AllowsSign` ---
end-to-end pool drive against committed AMD Milan SEV-SNP
fixture; output verifies under `magnetar.VerifyBytes` (no
caller awareness of the pool's existence).
- `TestMagnetarCombine_StaleAttestation_RejectsSign` --- members
outside rotation window refused; partial re-attestation
recovers.
- `TestMagnetarCombine_TwoOfThreeAttestedCombiners_MatchSig` ---
2-of-3 quorum surfaces signature; 1-of-3 stops.
- `TestMagnetarCombine_SignatureDivergence_HardRefusal` --- pool
refuses byte-divergent quorum output (no silent winner-picking).
All five tests pass under `-race` against the committed Milan
SEV-SNP fixture (`pkg/thresholdd/testdata/sev_snp_attestation_milan.bin`,
`sev_snp_vcek_milan.cer`) replayed via `dispatchKDSReplay()`.
---
**Document metadata**
- Name: `TEE-INTEGRATION.md`
- Date: 2026-06-03
- Pin: Magnetar v1.2 + slhdsa-tee at commit b1c0..f8d