mirror of
https://github.com/luxfi/magnetar.git
synced 2026-09-24 00:25:23 +00:00
Introduce TWO new signing modes plus a clarifying rename of the legacy
v0.1 path.
1. pkg/thbs/ — TRUE threshold hash-based signatures in the McGrew et al.
sense (IACR ePrint 2019/793 / IRTF draft-mcgrew-hash-sigs line). For
HBS schemes the signature reveals SELECTED secret elements (WOTS+
chain heads selected by the message-digest base-w digits + FORS
secret leaves selected by the FORS index digest). Threshold signing
here Shamir-shares each secret element across the committee; for
each message parties release shares ONLY for the SELECTED elements;
the combiner Lagrange-reconstructs just those elements; the
verifier sees an ordinary HBS-style signature.
Subpackage layout:
- thbs.go — types per the requested API shape (DKGConfig,
PublicKey, PrivateShare, PartialSignature,
FinalSignature, Evidence, EquivocationError).
- dealer.go — v1 dealer-backed DKG. The dealer Shamir-shares each
secret element across the committee via per-byte
GF(257); the dealer seed is zeroised before return.
v2 will replace with public DKG.
- wots.go — WOTS+ (Winternitz w=16, FIPS 205-style base-w digit
+ checksum decomposition; cSHAKE-256 hash chains).
- fors.go — FORS (k subtrees, height a, per-leaf binary Merkle).
- tree.go — public Merkle tree over WOTS+ leaf-roots.
- slot.go — anti-equivocation slot guard. Same-slot-different-
digest emits Evidence{party, slot, digest_a/b,
share_a/b} for the slashing layer.
- sign.go — SignShare + Aggregate + Verify.
- shamir.go — byte-wise Shamir over GF(257); elements are shared
directly, not seeds.
- hash.go — cSHAKE-256 with the "Magnetar-THBS" function-name
and per-tag domain separation.
24 unit tests pin every invariant: no-seed-exposure,
selected-elements-only for both WOTS+ and FORS, t-of-n threshold,
anti-equivocation, cross-slot/cross-message rejection, tamper
detection.
Honest v1 scope (documented in THBS-SPEC.md):
- Setup is DEALER-BACKED. v2 replaces with public DKG.
- Helper data shipped alongside the public key (McGrew et al.
permit this).
- Verifier is a CUSTOM HBS verifier; v3 will produce FIPS 205-byte-
identical output.
Hard invariant enforced by the package shape:
OK: reconstructElement(slot, elementID, shares)
Forbidden: ReconstructSeed, ReconstructPrivateKey,
ExpandPrivateKey, DeriveAllFutureElements
The only Reconstruct symbol in thbs/*.go is the unexported
reconstructElement in shamir.go.
2. pkg/magnetar/aggregate.go — public-BFT-safe N-of-N collected
signatures. Each validator holds its OWN SLH-DSA keypair (no DKG,
no shared seed). Primitives: GenerateValidatorKey, SignBundle,
VerifyBundle, AggregateSignatures, VerifyAggregated. 10 tests.
3. pkg/magnetar/combine.go — Combine renamed to
CombineWithSeedReconstruction throughout the package + callers
(e2e_test, threshold_test, n1_byte_equality_test, fuzz_test,
genkat, ct/dudect bridge) to make the TEE-only trust caveat
explicit at the API surface. KAT byte-equality preserved: the
function body is unchanged.
Refs: McGrew, Fluhrer, Gazdag, Kampanakis, Morton, Westerbaan,
"Coalition and Threshold Hash-Based Signatures" (IACR ePrint 2019/793);
Bonte, Smart, Tan, "Threshold SPHINCS+", PKC 2024 (the negative result
informing our v1-ships-a-custom-HBS-verifier scope choice).
Magnetar constant-time analysis — dudect harness
This directory holds the dudect harness (https://github.com/oreparaz/dudect) that drives empirical constant-time testing on Magnetar's Verify and Combine paths.
Targets
| Target | What it tests | Operationally-meaningful CT? |
|---|---|---|
dudect_verify |
magnetar.Verify(pk, msg, ctx, sig) over a pool of VALID signatures |
Yes — Verify is the consensus-consumer hot path; CT means an attacker can't extract sig content from timing |
dudect_combine |
magnetar.CombineWithSeedReconstruction(...) over a pool of VALID Round-1+Round-2 tapes (independent ceremonies over the SAME shares; all produce the SAME final signature) |
Yes — CombineWithSeedReconstruction reconstructs the master seed in memory; CT means the seed value can't influence the leakage trace |
The valid-pool design is the same operationally-meaningful CT
framing Pulsar uses (~/work/lux/pulsar/ct/dudect/). Earlier
versions of the harness used class A = zero bytes and class B =
random bytes — both INVALID — which produced rejection-path timing
artifacts rather than data-dependent secret leaks.
Build
./fetch.sh # pulls dudect at the pinned commit
make # builds both dudect_verify + dudect_combine
make verify # just verify
make combine # just combine
Run
Smoke test (laptop, ~minute per target):
./dudect_verify
./dudect_combine
Full submission-grade run (10^9 samples on a pinned CPU, quiet host):
DUDECT_SAMPLES=1000000 DUDECT_MAX_BATCHES=1000 ./dudect_verify
DUDECT_SAMPLES=500000 DUDECT_MAX_BATCHES=1000 ./dudect_combine
Or use the orchestrator: ./run-submission.sh.
Host support
- x86_64 Linux/macOS: builds cleanly against upstream dudect.h.
- aarch64 Linux/macOS:
dudect_compat.his force-included on AArch64 hosts to supply ARM equivalents of_mm_mfence()and__rdtsc().
What this is NOT
- dudect is an EMPIRICAL CT validator; a negative result (no leakage
detected) is evidence but not proof. The corresponding FORMAL CT
artifacts live in
../../jasmin/(when libjade-SLH-DSA lands; see../../jasmin/slh-dsa/README.md). - The smoke-test budget (10,000 samples) is INSUFFICIENT for a CT
certification claim. The full NIST submission requires ~10^9
samples per target. See
run-submission.sh. - Constant-time analysis at this level does NOT address:
- cache-timing side channels
- power side channels
- EM side channels
- fault attacks
- Spectre / Meltdown microarchitectural leakage