From 6a3a8653dd007ad2331512761a6817c1d5db4da7 Mon Sep 17 00:00:00 2001 From: Hanzo AI Date: Wed, 3 Jun 2026 11:45:40 -0700 Subject: [PATCH] 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] --- AUDIT-2026-06.md | 632 +++++++++++++++++++++++++++++++++++++++++++++ BLOCKERS.md | 50 ++++ GPU-PORT-PLAN.md | 450 ++++++++++++++++++++++++++++++++ README.md | 10 + TEE-INTEGRATION.md | 383 +++++++++++++++++++++++++++ 5 files changed, 1525 insertions(+) create mode 100644 AUDIT-2026-06.md create mode 100644 GPU-PORT-PLAN.md create mode 100644 TEE-INTEGRATION.md diff --git a/AUDIT-2026-06.md b/AUDIT-2026-06.md new file mode 100644 index 0000000..6cfd775 --- /dev/null +++ b/AUDIT-2026-06.md @@ -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` diff --git a/BLOCKERS.md b/BLOCKERS.md index e62bd95..7113470 100644 --- a/BLOCKERS.md +++ b/BLOCKERS.md @@ -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 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 - 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 CT track: `ct/README.md` - 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` diff --git a/GPU-PORT-PLAN.md b/GPU-PORT-PLAN.md new file mode 100644 index 0000000..ec259c8 --- /dev/null +++ b/GPU-PORT-PLAN.md @@ -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` diff --git a/README.md b/README.md index df04798..1335e69 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,16 @@ M-LWE + Corona R-LWE) with hash-based PQ (Magnetar SLH-DSA). - `LICENSING.md` --- license terms. - `SUBMISSION.md` / `NIST-SUBMISSION.md` / `SUBMISSION-STATUS.md` --- 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 diff --git a/TEE-INTEGRATION.md b/TEE-INTEGRATION.md new file mode 100644 index 0000000..5808e0a --- /dev/null +++ b/TEE-INTEGRATION.md @@ -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