mirror of
https://github.com/luxfi/pulsar.git
synced 2026-09-24 00:25:52 +00:00
pulsar: dealerless ML-DSA DKG obstruction, derived not asserted (PULSAR-V12 Part 2)
Genuinely-dealerless DKG producing byte-FIPS-204 ML-DSA keys is NOT achievable with known techniques. This commit COMPUTES why (mirroring rangeproof.go's derive-don't-assert pattern) rather than faking a key or falling back to a dealer/TEE. THE OBSTRUCTION (precise): FIPS-204 draws s1,s2 from S_eta (||.||inf <= eta) and calibrates beta=tau*eta, omega, and the BCC 2*beta boundary margin to that. A dealerless DKG forms the joint secret as a sum/Lagrange-combination of N>=2 contributions => ||s2||inf <= N*eta, so ||c*s2||inf <= N*beta > beta, violating the BCC boundary-clearance hypothesis ||c*s2||inf <= beta. assessDealerlessFIPS computes N*beta vs beta and shows byte-validity breaks at N=2 for both ML-DSA-65 and -87; the deeper break is that a sum-of-contributions secret is not the S_eta distribution ML-DSA's EUF-CMA assumes. Forcing the joint into S_eta needs either a dealer or a norm-reduction that changes (A,t) => not byte-compatible. NOT the obstruction: t0. The joint t0 = Power2Round-low(joint t) is in (-2^(d-1), 2^(d-1)] by definition for ANY N, so ||c*t0||inf <= tau*2^(d-1) < gamma2 always. Pinned by TestDealerless_T0IsNotTheObstruction (200704/245760 < 261888). CORONA/RACCOON noise-flooding assessed: corona.BootstrapPedersen is dealerless because Ring-LWE is noise-flooded (beta_j = A*(lambda_j*s_j)+e_j', sigma=kappa*sigmaE*sqrt(n)) with a Round_Xi absorption step; ML-DSA has fixed S_eta bounds and no absorbing rounding, so any flooded variant is a Raccoon-family scheme (Threshold Raccoon, EUROCRYPT'24) that does NOT verify under FIPS-204. This is exactly why the Quasar cert is AND-mode dual-PQ: dealerless Corona leg || dealer/TEE-genesis Pulsar leg. DealerlessMLDSADKG fails closed (ErrDealerlessByteFIPSUnreachable), never fakes, never falls back to dealer/TEE. 5 tests pin the arithmetic.
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package pulsar
|
||||
|
||||
// distributed_bcc_dkg.go — the dealerless-DKG obstruction for byte-FIPS-204
|
||||
// ML-DSA, DERIVED from the parameter arithmetic (not asserted). This is the
|
||||
// honest Part-2 deliverable of PULSAR-V12-PARALLEL-PQ: a genuinely
|
||||
// dealerless DKG that produces a key whose signatures verify byte-for-byte
|
||||
// under unmodified FIPS 204 is NOT achievable with known techniques, and
|
||||
// THIS FILE COMPUTES WHY rather than faking a key or falling back to a
|
||||
// dealer/TEE.
|
||||
//
|
||||
// It mirrors rangeproof.go's pattern: the fail-closed decision is a
|
||||
// COMPUTED consequence of the FIPS 204 bounds (assessDealerlessFIPS), and a
|
||||
// test (distributed_bcc_dkg_test.go) pins the arithmetic so the obstruction
|
||||
// is reproducible, not a claim.
|
||||
//
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// THE OBSTRUCTION (precise; which step breaks).
|
||||
//
|
||||
// FIPS 204 KeyGen samples s1, s2 UNIFORMLY from S_η = {p ∈ R : ‖p‖∞ ≤ η}.
|
||||
// The ENTIRE parameter set is calibrated to ‖s1‖∞, ‖s2‖∞ ≤ η:
|
||||
//
|
||||
// β = τ·η — the verifier's ‖z‖∞ < γ1 − β ceiling AND the bound on the
|
||||
// key-dependent shift ‖c·s2‖∞ ≤ β,
|
||||
// ω — the hint weight bound,
|
||||
// 2β margin — the BCC boundary-clearance slack (boundary.go
|
||||
// boundaryThreshold = γ2 − 2β − slack) that guarantees
|
||||
// HighBits(w − c·s2) = HighBits(w) for the no-leak hint.
|
||||
//
|
||||
// A dealerless DKG (Pedersen/Gennaro: no party knows the secret) forms the
|
||||
// joint secret as a SUM / Lagrange combination of N ≥ 2 independent
|
||||
// contributions, each itself in S_η. The result is NOT S_η-distributed and
|
||||
// has ℓ∞-support up to N·η > η. Then:
|
||||
//
|
||||
// 1. BYTE-VALIDITY breaks at the BCC boundary-clearance hypothesis. The
|
||||
// fixed 2β margin certifies HighBits stability ONLY when ‖c·s2‖∞ ≤ β,
|
||||
// i.e. ‖s2‖∞ ≤ η. With ‖s2‖∞ ≤ N·η the shift is ‖c·s2‖∞ ≤ N·β, so a
|
||||
// nonce passing the FIXED-margin BoundaryClear can still have
|
||||
// HighBits(w − c·s2) ≠ HighBits(w) ⇒ FindHint cannot reach w1 ⇒ NO
|
||||
// FIPS-204-valid signature. The BCC correctness theorem's hypothesis is
|
||||
// violated for every N ≥ 2 (assessDealerlessFIPS computes N·β vs β).
|
||||
// Enlarging the margin to 2N·β is non-standard (it changes the
|
||||
// protocol, and the yield falls to zero as N → γ2/2β); it does not
|
||||
// restore FIPS-204 byte-compatibility, and it still leaves (2).
|
||||
//
|
||||
// 2. SECURITY EQUIVALENCE breaks regardless of (1). ML-DSA's EUF-CMA
|
||||
// reduction and concrete MLWE/Module-SIS hardness are stated for the
|
||||
// S_η secret distribution. A sum-of-contributions secret is a different
|
||||
// (and efficiently distinguishable) distribution; the FIPS-204 security
|
||||
// claim does not transfer.
|
||||
//
|
||||
// 3. FORCING the joint secret back into S_η is infeasible. Rejection-
|
||||
// sampling the joint into S_η requires every one of (L+K)·256
|
||||
// coefficients to independently land in [−η, η]; the acceptance
|
||||
// probability is (≈ (2η+1)/q)^… — negligible. A norm-reduction MPC
|
||||
// would change the (A, t) relation and hence the public key, breaking
|
||||
// verifiability under the same key. Constraining a Shamir RECONSTRUCTION
|
||||
// to S_η without a party knowing the secret is exactly a dealer.
|
||||
//
|
||||
// NOT the obstruction: t0. The joint t0 = Power2Round-low(joint t) lies in
|
||||
// (−2^(d−1), 2^(d−1)] BY DEFINITION for ANY joint t, so ‖c·t0‖∞ ≤ τ·2^(d−1)
|
||||
// < γ2 holds for every N. The wall is the SECRET (s1, s2) distribution, not
|
||||
// the rounding residual. (assessDealerlessFIPS records this explicitly so
|
||||
// the t0 red herring is ruled out by computation.)
|
||||
//
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// THE CORONA / RACCOON NOISE-FLOODING ADAPTATION (assessed, honest verdict).
|
||||
//
|
||||
// Corona's keyera.BootstrapPedersen IS genuinely dealerless. It escapes the
|
||||
// wall above because corona is a NOISE-FLOODED Ring-LWE scheme, not ML-DSA:
|
||||
//
|
||||
// β_j = A·(λ_j·s_j) + e_j' with a fresh Gaussian e_j' ~ D(κ·σ_E·√n),
|
||||
// b = Σ_j β_j = A·s + e'' (the √n-grown flooding noise),
|
||||
// bTilde = Round_Ξ(b) (a rounding step that ABSORBS the noise).
|
||||
//
|
||||
// The √n-grown flooding noise is what LWE-protects each share, and corona's
|
||||
// verifier TOLERATES it because its bounds are set for flooded noise and the
|
||||
// Round_Ξ step folds the noise into the rounded public key. This is the
|
||||
// RIGHT technique for a threshold-friendly lattice signature — and it is
|
||||
// exactly why corona is dealerless.
|
||||
//
|
||||
// It does NOT adapt to byte-FIPS-204 ML-DSA. Noise-flooding deliberately
|
||||
// ENLARGES the secret/error norms beyond S_η; ML-DSA has NO noise-absorbing
|
||||
// rounding step (its t0 is the Power2Round residual, already consumed by the
|
||||
// hint), a FIXED β = τη ceiling, and a verifier with no slack for flooded
|
||||
// terms. Any noise-flooded / Gaussian-secret variant of ML-DSA is a
|
||||
// Raccoon-family scheme (del Pino–Katsumata–Prest–Rossi, "Threshold
|
||||
// Raccoon", EUROCRYPT 2024) with DIFFERENT parameters and a DIFFERENT
|
||||
// verifier — its signatures do not verify under FIPS 204. This is precisely
|
||||
// why the Quasar finality cert is AND-mode dual-PQ: a genuinely dealerless
|
||||
// CORONA (Ring-LWE, noise-flooded) leg in parallel with a dealer/TEE-genesis
|
||||
// PULSAR (FIPS-204 ML-DSA) leg. Permissionless safety rests on Corona; the
|
||||
// Pulsar leg is FIPS-204-standard defence-in-depth.
|
||||
//
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// CANDIDATE RESEARCH DIRECTIONS (none ships byte-FIPS-204 dealerless today).
|
||||
//
|
||||
// 1. Threshold-friendly variant (NOT byte-ML-DSA): Threshold Raccoon /
|
||||
// NIST MPTC. Accepts a non-FIPS verifier; this is what Corona already
|
||||
// provides for the dealerless lane.
|
||||
// 2. Distributed-rejection DKG with an EXACT ℓ∞ lattice range proof: each
|
||||
// party proves the joint secret ∈ S_η and the cohort resamples on
|
||||
// failure. Blocked twice: the exact ℓ∞ range proof does not exist in
|
||||
// this package (rangeproof.go: the available constructions certify ℓ2,
|
||||
// not ℓ∞), and the sum-lands-in-S_η acceptance probability is negligible.
|
||||
// 3. Verifiable pseudorandom secret sharing whose reconstruction is in S_η
|
||||
// by construction — open for ML-DSA's exact distribution.
|
||||
// 4. MPC-with-abort genesis (e.g. garbled-circuit KeyGen) that never
|
||||
// materialises the secret on one node — heavyweight, and sampling S_η
|
||||
// uniformly inside the MPC is the hard part; not "dealerless" in the
|
||||
// Pedersen sense.
|
||||
|
||||
import "errors"
|
||||
|
||||
// ErrDealerlessByteFIPSUnreachable is returned by DealerlessMLDSADKG. A
|
||||
// genuinely dealerless DKG producing byte-FIPS-204 ML-DSA keys is not
|
||||
// achievable with known techniques (see the file header). This entry point
|
||||
// fails closed — it NEVER fakes a key and NEVER silently falls back to a
|
||||
// trusted dealer or a TEE (those are the explicit, opt-in DealAlgShares /
|
||||
// mldsa-tee paths). Production dealerless genesis is Corona's job in the
|
||||
// AND-mode dual-PQ cert.
|
||||
var ErrDealerlessByteFIPSUnreachable = errors.New(
|
||||
"pulsar: dealerless byte-FIPS-204 ML-DSA DKG is not achievable — a " +
|
||||
"dealerless joint secret is a sum of N≥2 contributions with ‖s2‖∞ ≤ Nη, " +
|
||||
"violating the BCC boundary-clearance hypothesis ‖c·s2‖∞ ≤ β (and ML-DSA's " +
|
||||
"S_η-calibrated EUF-CMA); use DealAlgShares (dealer/TEE genesis) for the " +
|
||||
"Pulsar leg and rely on the dealerless Corona leg for permissionless safety")
|
||||
|
||||
// DealerlessFIPSObstruction is the COMPUTED obstruction for a dealerless DKG
|
||||
// over `parties` contributors at a given parameter set. Every field is
|
||||
// derived from the FIPS 204 bounds; the test pins them. ByteFIPSReachable is
|
||||
// true only in the degenerate single-contributor case (which is a dealer).
|
||||
type DealerlessFIPSObstruction struct {
|
||||
Mode Mode
|
||||
Parties int
|
||||
|
||||
Eta uint32 // η — the FIPS 204 S_η secret bound
|
||||
Tau uint32 // τ — challenge weight
|
||||
Beta uint32 // β = τ·η — the calibrated ‖c·s2‖∞ ≤ β bound + ‖z‖ ceiling slack
|
||||
Gamma2 uint32 // γ2 — the HighBits bucket half-width
|
||||
T0Bound uint32 // 2^(d−1) — the Power2Round residual bound
|
||||
|
||||
// Joint-secret norm growth under a dealerless sum of `parties`
|
||||
// contributions, each in S_η.
|
||||
JointS2Linf uint32 // worst-case ‖s2_joint‖∞ ≤ parties·η
|
||||
JointCS2Linf uint32 // worst-case ‖c·s2_joint‖∞ ≤ parties·β
|
||||
BCCMarginCovers uint32 // the shift the FIXED 2β margin certifies: ≤ β
|
||||
JointCT0Linf uint32 // worst-case ‖c·t0_joint‖∞ ≤ τ·2^(d−1) (N-INDEPENDENT)
|
||||
|
||||
// Derived verdicts.
|
||||
BoundaryHypothesisHolds bool // JointCS2Linf ≤ BCCMarginCovers (β)
|
||||
T0BoundHolds bool // JointCT0Linf < Gamma2 (always true — t0 via Power2Round)
|
||||
ByteFIPSReachable bool // BoundaryHypothesisHolds && parties ≤ 1
|
||||
}
|
||||
|
||||
// assessDealerlessFIPS computes the dealerless-DKG obstruction for `parties`
|
||||
// contributors at `mode`. It is the single source of truth for the
|
||||
// fail-closed decision: ByteFIPSReachable is false for every real dealerless
|
||||
// committee (parties ≥ 2), and the reason is the boundary-clearance
|
||||
// hypothesis ‖c·s2‖∞ ≤ β, computed here as JointCS2Linf vs BCCMarginCovers.
|
||||
//
|
||||
// ok=false for parameter sets outside the BCC-proven scope (ML-DSA-44),
|
||||
// where the no-leak signing path itself does not apply.
|
||||
func assessDealerlessFIPS(mode Mode, parties int) (DealerlessFIPSObstruction, bool) {
|
||||
gamma2, beta, _, ok := bccParams(mode)
|
||||
if !ok {
|
||||
return DealerlessFIPSObstruction{}, false
|
||||
}
|
||||
tau, _, _, _ := modeTauOmega(mode)
|
||||
_, _, eta := modeShape(mode)
|
||||
if parties < 1 {
|
||||
parties = 1
|
||||
}
|
||||
n := uint32(parties)
|
||||
t0Bound := uint32(1) << (bccD - 1)
|
||||
|
||||
o := DealerlessFIPSObstruction{
|
||||
Mode: mode,
|
||||
Parties: parties,
|
||||
Eta: eta,
|
||||
Tau: uint32(tau),
|
||||
Beta: beta,
|
||||
Gamma2: gamma2,
|
||||
T0Bound: t0Bound,
|
||||
|
||||
// Dealerless sum of N S_η contributions: ‖s2_joint‖∞ ≤ N·η.
|
||||
JointS2Linf: n * eta,
|
||||
JointCS2Linf: n * beta, // ‖c·s2_joint‖∞ ≤ τ·(N·η) = N·β
|
||||
// The FIXED BCC margin (boundary.go) certifies HighBits stability for
|
||||
// a shift of magnitude ≤ β only.
|
||||
BCCMarginCovers: beta,
|
||||
// t0 = Power2Round-low(joint t): in (−2^(d−1), 2^(d−1)] for ANY joint
|
||||
// t, so ‖c·t0‖∞ ≤ τ·2^(d−1), INDEPENDENT of N.
|
||||
JointCT0Linf: uint32(tau) * t0Bound,
|
||||
}
|
||||
o.BoundaryHypothesisHolds = o.JointCS2Linf <= o.BCCMarginCovers
|
||||
o.T0BoundHolds = o.JointCT0Linf < o.Gamma2
|
||||
o.ByteFIPSReachable = o.BoundaryHypothesisHolds && parties <= 1
|
||||
return o, true
|
||||
}
|
||||
|
||||
// DealerlessMLDSADKG is the fail-closed dealerless-DKG entry point. There is
|
||||
// no byte-FIPS-204 dealerless construction (see the file header and
|
||||
// assessDealerlessFIPS), so for any real committee (parties ≥ 2) it returns
|
||||
// ErrDealerlessByteFIPSUnreachable with the COMPUTED obstruction. It NEVER
|
||||
// fabricates a key and NEVER falls back to a dealer/TEE — those are the
|
||||
// explicit, opt-in DealAlgShares / mldsa-tee paths a caller must choose by
|
||||
// name. The Corona leg provides the dealerless guarantee in the AND-mode
|
||||
// dual-PQ cert.
|
||||
func DealerlessMLDSADKG(params *Params, committee []NodeID, threshold int) (*DealerlessFIPSObstruction, error) {
|
||||
if err := params.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o, ok := assessDealerlessFIPS(params.Mode, len(committee))
|
||||
if !ok {
|
||||
return nil, ErrBCCParamSet
|
||||
}
|
||||
if o.ByteFIPSReachable {
|
||||
// parties ≤ 1 — degenerate (a single contributor is a dealer). There
|
||||
// is no dealerless setting to satisfy; route through DealAlgShares.
|
||||
return &o, ErrDealerlessByteFIPSUnreachable
|
||||
}
|
||||
return &o, ErrDealerlessByteFIPSUnreachable
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package pulsar
|
||||
|
||||
// distributed_bcc_dkg_test.go — pins the dealerless-DKG obstruction
|
||||
// arithmetic. The fail-closed Part-2 verdict is DERIVED from the FIPS 204
|
||||
// bounds (distributed_bcc_dkg.go assessDealerlessFIPS), and these tests
|
||||
// reproduce every load-bearing number so the obstruction is computable, not
|
||||
// asserted. They also rule out the t0 red herring by computation.
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestDealerless_BoundaryHypothesisBreaksAtTwoParties is the load-bearing
|
||||
// computation: a dealerless joint secret summed over N ≥ 2 contributions has
|
||||
// ‖c·s2‖∞ ≤ N·β, which exceeds the FIXED BCC boundary margin's β-coverage
|
||||
// for every N ≥ 2 — so no FIPS-204-valid no-leak signature exists. N = 1
|
||||
// (the degenerate single-contributor = dealer) is the only case the
|
||||
// hypothesis holds.
|
||||
func TestDealerless_BoundaryHypothesisBreaksAtTwoParties(t *testing.T) {
|
||||
for _, mode := range []Mode{ModeP65, ModeP87} {
|
||||
o1, ok := assessDealerlessFIPS(mode, 1)
|
||||
if !ok {
|
||||
t.Fatalf("%s should be in BCC scope", mode)
|
||||
}
|
||||
if !o1.BoundaryHypothesisHolds {
|
||||
t.Fatalf("%s N=1: boundary hypothesis must hold (‖c·s2‖∞=%d ≤ β=%d)",
|
||||
mode, o1.JointCS2Linf, o1.BCCMarginCovers)
|
||||
}
|
||||
if o1.JointCS2Linf != o1.Beta {
|
||||
t.Fatalf("%s N=1: ‖c·s2‖∞ should equal β=%d, got %d", mode, o1.Beta, o1.JointCS2Linf)
|
||||
}
|
||||
|
||||
for n := 2; n <= 8; n++ {
|
||||
o, _ := assessDealerlessFIPS(mode, n)
|
||||
if o.BoundaryHypothesisHolds {
|
||||
t.Fatalf("%s N=%d: boundary hypothesis must FAIL (‖c·s2‖∞=%d > β=%d) — the dealerless wall",
|
||||
mode, n, o.JointCS2Linf, o.BCCMarginCovers)
|
||||
}
|
||||
if o.JointCS2Linf != uint32(n)*o.Beta {
|
||||
t.Fatalf("%s N=%d: ‖c·s2‖∞ should be N·β=%d, got %d", mode, n, uint32(n)*o.Beta, o.JointCS2Linf)
|
||||
}
|
||||
if o.ByteFIPSReachable {
|
||||
t.Fatalf("%s N=%d: byte-FIPS-204 must be UNREACHABLE dealerlessly", mode, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestDealerless_T0IsNotTheObstruction rules out the t0 red herring by
|
||||
// computation: t0 = Power2Round-low(joint t) ∈ (−2^(d−1), 2^(d−1)] for ANY
|
||||
// joint t, so ‖c·t0‖∞ ≤ τ·2^(d−1) < γ2 holds for EVERY N. The wall is the
|
||||
// secret (s1, s2) distribution, never t0.
|
||||
func TestDealerless_T0IsNotTheObstruction(t *testing.T) {
|
||||
cases := map[Mode]uint32{
|
||||
ModeP65: 49 * 4096, // τ·2^(d−1) = 200704
|
||||
ModeP87: 60 * 4096, // τ·2^(d−1) = 245760
|
||||
}
|
||||
for mode, wantCT0 := range cases {
|
||||
for _, n := range []int{1, 2, 5, 100, 1000} {
|
||||
o, _ := assessDealerlessFIPS(mode, n)
|
||||
if o.JointCT0Linf != wantCT0 {
|
||||
t.Fatalf("%s N=%d: ‖c·t0‖∞ should be %d (N-independent), got %d", mode, n, wantCT0, o.JointCT0Linf)
|
||||
}
|
||||
if !o.T0BoundHolds {
|
||||
t.Fatalf("%s N=%d: ‖c·t0‖∞=%d must stay < γ2=%d for all N (t0 is via Power2Round)",
|
||||
mode, n, o.JointCT0Linf, o.Gamma2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestDealerless_ExactParameterNumbers pins the concrete FIPS 204 numbers the
|
||||
// obstruction rests on, so a parameter drift is caught.
|
||||
func TestDealerless_ExactParameterNumbers(t *testing.T) {
|
||||
o65, _ := assessDealerlessFIPS(ModeP65, 2)
|
||||
if o65.Eta != 4 || o65.Tau != 49 || o65.Beta != 196 || o65.Gamma2 != 261888 || o65.T0Bound != 4096 {
|
||||
t.Fatalf("ML-DSA-65 parameters drifted: η=%d τ=%d β=%d γ2=%d 2^(d-1)=%d",
|
||||
o65.Eta, o65.Tau, o65.Beta, o65.Gamma2, o65.T0Bound)
|
||||
}
|
||||
// N=2 joint shift is 2β = 392, already over the β=196 the fixed margin covers.
|
||||
if o65.JointCS2Linf != 392 || o65.BCCMarginCovers != 196 {
|
||||
t.Fatalf("ML-DSA-65 N=2: ‖c·s2‖∞=%d (want 392) vs margin %d (want 196)", o65.JointCS2Linf, o65.BCCMarginCovers)
|
||||
}
|
||||
|
||||
o87, _ := assessDealerlessFIPS(ModeP87, 2)
|
||||
if o87.Eta != 2 || o87.Tau != 60 || o87.Beta != 120 || o87.Gamma2 != 261888 {
|
||||
t.Fatalf("ML-DSA-87 parameters drifted: η=%d τ=%d β=%d γ2=%d", o87.Eta, o87.Tau, o87.Beta, o87.Gamma2)
|
||||
}
|
||||
// ML-DSA-87 single-key c·t0 headroom is only ~6.2% of γ2 — tight but valid.
|
||||
if o87.JointCT0Linf != 245760 {
|
||||
t.Fatalf("ML-DSA-87 ‖c·t0‖∞ should be 245760, got %d", o87.JointCT0Linf)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDealerless_ML_DSA44_OutOfScope confirms the BCC scope gate: ML-DSA-44
|
||||
// is outside the proven no-leak scope, so the assessment reports ok=false.
|
||||
func TestDealerless_ML_DSA44_OutOfScope(t *testing.T) {
|
||||
if _, ok := assessDealerlessFIPS(ModeP44, 3); ok {
|
||||
t.Fatalf("ML-DSA-44 must be reported out of BCC scope")
|
||||
}
|
||||
}
|
||||
|
||||
// TestDealerless_EntryPointFailsClosed proves DealerlessMLDSADKG never fakes
|
||||
// a key and never silently falls back to a dealer/TEE: it returns the
|
||||
// computed obstruction with ErrDealerlessByteFIPSUnreachable for a real
|
||||
// committee.
|
||||
func TestDealerless_EntryPointFailsClosed(t *testing.T) {
|
||||
params := MustParamsFor(ModeP65)
|
||||
committee := make([]NodeID, 5)
|
||||
for i := range committee {
|
||||
committee[i][0] = byte(i + 1)
|
||||
}
|
||||
o, err := DealerlessMLDSADKG(params, committee, 3)
|
||||
if !errors.Is(err, ErrDealerlessByteFIPSUnreachable) {
|
||||
t.Fatalf("DealerlessMLDSADKG must fail closed, got err=%v", err)
|
||||
}
|
||||
if o == nil || o.ByteFIPSReachable {
|
||||
t.Fatalf("obstruction must report byte-FIPS unreachable for a 5-party committee")
|
||||
}
|
||||
if o.JointCS2Linf <= o.BCCMarginCovers {
|
||||
t.Fatalf("5-party ‖c·s2‖∞=%d must exceed the β=%d the fixed margin covers", o.JointCS2Linf, o.BCCMarginCovers)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user