mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
The forged certificate that reached crates.io was killed at verification, but a red review showed the hole had only moved to registration: a key was admitted on key_validate alone, which proves a point is on the curve and nothing about who holds its secret, and duplicate keys were merged into one validator carrying many node ids — so a floor written to require many distinct signers was cleared by one holder registering one key under several ids. This is the Go oracle for the standard ruled in luxfi/conformance: it defines the bytes Rust and C++ reproduce. validator/pop is the primitive. A registrant signs its own identity followed by its own key — node(20, ids.NodeID) ‖ pubkey(48, compressed G1), 68 bytes, no separator — under the proof-of-possession domain BLS_POP_..._POP_, distinct from the vote's ..._NUL_ so a vote is never a proof and a proof never a vote. The node is bound because the pubkey-only IETF proof travels with the key: bound to nothing, it re-registers under any identity. 20 bytes because a Lux validator's identity IS its NodeID; the 32-byte consensus Id names blocks, not nodes, and has no canonical inverse, so widening would invent a second name for one node. validator/registration is the admission rule, written once: encoding, then possession, then uniqueness, then weight — a pairing on non-points is undefined, and weight counted before uniqueness is weight counted twice. A set is admitted whole or refused whole, because a set that silently drops a signer no longer describes its own weight. FlattenValidatorSet's merge of duplicate keys is retired here: it was the only thing that made many-nodes-one-key representable, and after the uniqueness rule that state does not exist to normalize. Order and PublicKeyBytes still match the upstream flatten exactly, so a proven set and a flattened-distinct set are the same set. engine/chain keys the cert store on the DECISION — the signed canonical identity — not the transport envelope id, which no signature covers: two envelopes of one decision were two store entries for one finality fact, and a verified cert could be filed under a block it never attested. Keyed by decision, a cert is found by anything that finalized that decision, and Put is idempotent per decision. The pubkey-only P-chain proof (luxfi/node AddValidatorTx) is NOT touched here: moving it node-bound is a network upgrade, every validator re-proves, and it is activation-gated as the deliberate last step. Anywhere a validator set that shares a key across node ids is admitted today, this now refuses it — that is the intended behaviour, and the coordination point with the P-chain step. Co-authored-by: Hanzo Dev <[email protected]>
48 lines
1.5 KiB
Go
48 lines
1.5 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Package validators re-exports github.com/luxfi/validators.
|
|
package validators
|
|
|
|
import (
|
|
"github.com/luxfi/crypto/bls"
|
|
"github.com/luxfi/math/set"
|
|
"github.com/luxfi/validators"
|
|
)
|
|
|
|
// Sortable is an alias for validators.Sortable
|
|
type Sortable[T any] = validators.Sortable[T]
|
|
|
|
// Re-export errors
|
|
var (
|
|
ErrUnknownValidator = validators.ErrUnknownValidator
|
|
ErrWeightOverflow = validators.ErrWeightOverflow
|
|
)
|
|
|
|
// CanonicalValidatorSet is an alias for validators.CanonicalValidatorSet
|
|
type CanonicalValidatorSet = validators.CanonicalValidatorSet
|
|
|
|
// CanonicalValidator is an alias for validators.CanonicalValidator
|
|
type CanonicalValidator = validators.CanonicalValidator
|
|
|
|
// FlattenValidatorSet lives in registration.go: this package enforces one key
|
|
// per node, so the upstream merge of duplicate keys is not re-exported.
|
|
|
|
// FilterValidators re-exports validators.FilterValidators
|
|
func FilterValidators(
|
|
indices set.Bits,
|
|
vdrs []*CanonicalValidator,
|
|
) ([]*CanonicalValidator, error) {
|
|
return validators.FilterValidators(indices, vdrs)
|
|
}
|
|
|
|
// SumWeight re-exports validators.SumWeight
|
|
func SumWeight(vdrs []*CanonicalValidator) (uint64, error) {
|
|
return validators.SumWeight(vdrs)
|
|
}
|
|
|
|
// AggregatePublicKeys re-exports validators.AggregatePublicKeys
|
|
func AggregatePublicKeys(vdrs []*CanonicalValidator) (*bls.PublicKey, error) {
|
|
return validators.AggregatePublicKeys(vdrs)
|
|
}
|