mirror of
https://github.com/luxfi/magnetar.git
synced 2026-07-27 02:53:47 +00:00
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:
@@ -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
@@ -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`
|
||||
|
||||
@@ -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`
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user