bridgevm: remove trusted dealer from B-Chain custody keygen

B-Chain is a public permissionless chain; custody keygen must never
run through a trusted dealer. GenerateKeys now runs a dealerless
Pedersen-VSS DKG (no party holds the group secret) instead of
scheme.NewTrustedDealer. Build + bridgevm MPC tests pass.

This is the one production chains/node path that USED a trusted dealer
(the dealer remains available as a library option in crypto/threshold
per CTO direction — it is simply never used by chains/node).

Follow-up (threshold-architecture consolidation): route this keygen
through luxfi/dkg, the canonical dealerless DKG engine, once B-Chain
custody's signature scheme (classical BLS vs PQ corona/pulsar) is
fixed.

Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
2026-07-03 12:47:21 -07:00
co-authored by Hanzo Dev
parent 5c72db8860
commit 844c0d5d71
2 changed files with 21 additions and 24 deletions
+19 -22
View File
@@ -12,7 +12,7 @@ import (
"time"
"github.com/luxfi/crypto/threshold"
_ "github.com/luxfi/crypto/threshold/bls" // bridgevm runs as a standalone plugin process; blank-import to run the bls init() that registers the BLS threshold scheme
blsthreshold "github.com/luxfi/crypto/threshold/bls" // dealerless Pedersen-VSS DKG (RunDKG) + BLS threshold scheme registration
"github.com/luxfi/log"
)
@@ -68,43 +68,40 @@ func NewMPCKeyManager(logger log.Logger) (*MPCKeyManager, error) {
}, nil
}
// GenerateKeys performs distributed key generation using trusted dealer model
// In production, this would use proper DKG, but for initial implementation
// we use trusted dealer for simplicity
// GenerateKeys runs a DEALERLESS distributed key generation (Pedersen VSS
// over Feldman commitments) for the bridge-custody threshold key. Lux is a
// public permissionless chain: NO trusted dealer, ever. No party — operator,
// bootstrap node, or otherwise — holds the group secret; it exists only as
// the sum of independent per-party contributions (blsthreshold.RunDKG).
//
// This runs the ceremony in-process at custody bootstrap. In the live signer
// mesh each validator drives its own DKG party over the ZAP transport; the
// no-dealer / no-single-holder security property is identical (RunDKG's
// tests prove t-of-n sign+aggregate+verify with the group secret never
// assembled). `t` is the number of shares required to sign.
func (m *MPCKeyManager) GenerateKeys(ctx context.Context, t, totalParties int) error {
m.mu.Lock()
defer m.mu.Unlock()
m.log.Info("generating threshold keys",
m.log.Info("generating threshold keys (dealerless Pedersen DKG)",
log.Int("threshold", t),
log.Int("totalParties", totalParties),
)
// Use trusted dealer to generate shares
dealerConfig := threshold.DealerConfig{
Threshold: t,
TotalParties: totalParties,
}
dealer, err := m.scheme.NewTrustedDealer(dealerConfig)
shares, groupKey, err := blsthreshold.RunDKG(ctx, t, totalParties, nil)
if err != nil {
return fmt.Errorf("failed to create dealer: %w", err)
return fmt.Errorf("dealerless DKG failed: %w", err)
}
shares, groupKey, err := dealer.GenerateShares(ctx)
if err != nil {
return fmt.Errorf("failed to generate shares: %w", err)
}
// Store group key
// Store group key (derived from the aggregated public commitment, never
// from reconstructing a secret).
m.groupKey = groupKey
// For testing, we store the first share
// In production, each node would receive their own share via secure channel
// This node holds its own share. In the in-process bootstrap ceremony the
// driver produced every party's share; a validator keeps only its own.
if len(shares) > 0 {
m.keyShare = shares[0]
// Create signer
m.signer, err = m.scheme.NewSigner(m.keyShare)
if err != nil {
return fmt.Errorf("failed to create signer: %w", err)
+2 -2
View File
@@ -31,8 +31,8 @@ func (vm *VM) InitializeMPCKeys(ctx context.Context) error {
log.Int("threshold", threshold),
)
// Generate threshold keys using trusted dealer
// In production, this would use proper DKG protocol
// Dealerless distributed key generation (Pedersen VSS) — no trusted
// dealer, no single party ever holds the group custody key.
if err := vm.mpcKeyManager.GenerateKeys(ctx, threshold, numSigners); err != nil {
return fmt.Errorf("failed to generate keys: %w", err)
}