keys

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 7, 2026 License: BSD-3-Clause Imports: 28 Imported by: 3

Documentation

Overview

Package keys provides validator key management for Lux networks. It handles generation, loading, and storage of: - TLS staking keys (for node identity) - BLS signer keys (for validator consensus) - EC private keys (for P/X/C-chain addresses)

Index

Constants

View Source
const (
	MicroLux uint64 = 1                       // Base unit (6 decimals)
	Lux      uint64 = 1_000_000               // 10^6 microLux
	KiloLux  uint64 = 1_000 * Lux             // 10^9
	MegaLux  uint64 = 1_000_000 * Lux         // 10^12
	GigaLux  uint64 = 1_000_000_000 * Lux     // 10^15 (1B LUX)
	TeraLux  uint64 = 1_000_000_000_000 * Lux // 10^18 (1T LUX)

	// C-chain uses 18 decimals (wei), P/X-chain use 6 decimals
	// Multiply P-chain amount by this to get C-chain wei
	CChainDecimalShift = 1_000_000_000_000 // 10^12

	// Default validator stake: 1M LUX
	DefaultValidatorStake = MegaLux

	// Default fee account amount: 10M LUX (for chain creation, transactions)
	DefaultFeeAccountAmount = 10 * MegaLux
)

Unit constants for LUX amounts

View Source
const BIP44Purpose = 44

BIP44Purpose is the BIP-44 purpose constant. Pinned to 44 even though service identities don't carry funds — staying inside the BIP-44 purpose tree keeps the same mnemonic interoperable with the Lux wallet's existing derivation tree.

View Source
const CoinTypeEVM = 60

CoinTypeEVM is the SLIP-0044 coin_type for EVM chains (60', shared with Ethereum). C-Chain and any non-Lux L1 EVM derive under this tree.

View Source
const CoinTypeUTXO = 9000

CoinTypeUTXO is the SLIP-0044 coin_type for the UTXO-layout DAG-like chains — X-Chain (AVM) + P-Chain. Service identities derive under m/44'/9000'/<serviceIndex>'/0'/0' so they share the coin-type tree with X/P staking keys but never collide with account-zero derivations (serviceIndex is hashed from servicePath, never 0 in practice for any well-formed path).

View Source
const EnvelopeDomain = "lux-svc-envelope-v1"

EnvelopeDomain is the customisation prefix mixed into every envelope signature so signatures from one envelope shape (a KMS opcode call) cannot be replayed against another (e.g. a future RPC over the same wire). Pinned at v1.

View Source
const HybridBoundDigestLen = 48

HybridBoundDigestLen is the byte length of the m_bound digest the scheme uses internally. 48 bytes = SHAKE256-384, the same hash size as ids.FullDigest — matches the Lux convention for identity digests.

View Source
const HybridClassicalDomain = "lux-hybrid-classical-secp256k1-v1"

HybridClassicalDomain is the SHAKE256 customisation string for the secp256k1 component's scalar derivation. Pinned at v1.

View Source
const HybridClassicalLeafIndex uint32 = 0

HybridClassicalLeafIndex is the BIP-32 leaf index for the secp256k1 (classical) component of a hybrid validator identity. Pinned at 0 so it coincides with the existing ML-DSA-65-only service identity leaf — a hybrid identity is a superset, never a different tree position.

View Source
const HybridPQDomain = "lux-hybrid-pq-mldsa65-v1"

HybridPQDomain is the SHAKE256 customisation string for the ML-DSA-65 component's seed derivation. Pinned at v1. Distinct from serviceIdentityDomain so a hybrid identity's PQ key is NEVER the same byte-string as the legacy ML-DSA-only identity at the same path — the two derivations are cryptographically separated.

View Source
const HybridPQLeafIndex uint32 = 1

HybridPQLeafIndex is the BIP-32 leaf index for the ML-DSA-65 (PQ) component of a hybrid validator identity. Pinned at 1 so the PQ key derives at a sibling sub-path m/44'/9000'/serviceIndex'/0'/1' — distinct from the classical leaf and from the legacy ML-DSA-only leaf at index 0. The legacy path is preserved exactly; the new PQ leaf is purely additive.

View Source
const HybridSigDomain = "lux-hybrid-sig-v1"

HybridSigDomain is the canonical domain-separation string for the Lux hybrid signature scheme. Pinned at v1; bumping invalidates every prior hybrid signature, which is the correct behaviour for a hardfork of the binding encoding. The same string is used both as the H_bind prefix and as the ML-DSA-65 context.

Variables

View Source
var (
	// ErrHybridNilKey — either component of the hybrid key is nil.
	// Refused early; we never want a half-hybrid signing path.
	ErrHybridNilKey = errors.New("keys: hybrid key has nil component")

	// ErrHybridClassicalSign — secp256k1 signing failed. The error
	// wraps the underlying secp256k1 error.
	ErrHybridClassicalSign = errors.New("keys: hybrid classical sign failed")

	// ErrHybridPQSign — ML-DSA-65 signing failed. The error wraps
	// the underlying mldsa error.
	ErrHybridPQSign = errors.New("keys: hybrid PQ sign failed")

	// ErrHybridClassicalVerify — secp256k1 verification failed.
	// A valid hybrid signature requires BOTH components to verify.
	ErrHybridClassicalVerify = errors.New("keys: hybrid classical verification failed")

	// ErrHybridPQVerify — ML-DSA-65 verification failed. A valid
	// hybrid signature requires BOTH components to verify.
	ErrHybridPQVerify = errors.New("keys: hybrid PQ verification failed")

	// ErrHybridNilSig — signature struct or one of its components is
	// nil/empty. Refused before any expensive verification.
	ErrHybridNilSig = errors.New("keys: hybrid signature has nil component")
)

Typed errors. errors.Is friendly.

View Source
var ErrInvalidServicePath = errors.New("keys: service path is required")

ErrInvalidServicePath is returned when the servicePath argument is empty after trim. Empty paths would collapse every service to the same NodeID, which would silently mask configuration drift.

View Source
var ServiceChainID = mustHashChainID("lux-service-identity")

ServiceChainID is the well-known chain identifier under which all service NodeIDs are derived. Distinct from any L1 chain ID so a service NodeID never accidentally validates against a chain's validator-set commitment. Set once and never bumped — the empty "service" string is the canonical seed.

Use the helper ServiceChainIDForCluster if a deployment ever needs per-cluster service NodeID separation. The default (empty seed) is what every Hanzo cluster uses today.

Functions

func HybridBoundDigest added in v1.1.0

func HybridBoundDigest(pk *HybridPublicKey, msg []byte) ([]byte, error)

HybridBoundDigest is the exported helper computing m_bound. Same algorithm as the internal boundDigest; exported so an out-of-band verifier (e.g. an on-chain precompile or a different language's implementation) can reconstruct the bound message verbatim.

Pure function: no I/O, no randomness.

func HybridPublicKeyBytes added in v1.1.0

func HybridPublicKeyBytes(pk *HybridPublicKey) ([]byte, error)

HybridPublicKeyBytes returns the canonical wire encoding of the joint public key:

left_encode(8·|pk_classical|) || pk_classical
left_encode(8·|pk_pq|)        || pk_pq

This is the same framing m_bound uses for the joint pubkey, minus the domain prefix and msg. The encoding is unambiguous and can be reversed (each field's length is recoverable from its left_encode header).

Used to compute a hybrid NodeID via the existing ids.NodeIDScheme derivation — the scheme produces NodeID = SHAKE256-384("NODE_ID_V1" || chainID || scheme_byte || pubkey)[:20], so passing the wire-form hybrid pubkey here yields a NodeID committed to BOTH components.

func HybridVerify added in v1.1.0

func HybridVerify(pk *HybridPublicKey, msg []byte, sig *HybridSignature) error

HybridVerify checks a BBF-bound joint signature. Returns nil on success; returns a typed error identifying which component failed (or ErrHybridNilKey/ErrHybridNilSig for input errors).

BOTH components MUST verify. This is the AND-mode binding: a signature where only one component verifies is a forgery (or a substitution attempt) and MUST be refused.

The verification is order-independent: classical-first matches the natural reading of the construction, but a verifier could equally check PQ first. Either way, BOTH must pass.

func LoadMnemonic

func LoadMnemonic(ctx context.Context, addr, env, path string) (string, error)

LoadMnemonic returns the BIP-39 mnemonic for the calling service. MNEMONIC env wins when set; otherwise dials KMS over native ZAP at `addr` and reads the secret at `path` under `env`.

ctx   cancellable context
addr  KMS host:port (e.g. "liquid-kms.liquidity.svc:9999")
env   KMS env scope ("mainnet" | "testnet" | "devnet")
path  KMS secret path (e.g. "/mnemonic" or "/foo/master")

Returns the validated BIP-39 phrase. Caller is responsible for keeping it on the goroutine stack and not logging / persisting it.

func LoadMnemonicFromKMS

func LoadMnemonicFromKMS(ctx context.Context, addr, env, path string) (string, error)

LoadMnemonicFromKMS is the production-only path (no MNEMONIC env short-circuit). Useful when a caller wants to force the KMS read regardless of ambient env — e.g., a regression test pinning the production code path.

func ServiceChainIDForCluster added in v1.0.10

func ServiceChainIDForCluster(clusterSeed string) ids.ID

ServiceChainIDForCluster is a future hook for per-cluster NodeID separation. Today every Hanzo cluster shares ServiceChainID; if a future deployment ever needs to isolate two clusters' NodeID spaces (e.g. lux-mainnet vs hanzo-prod), the operator can override ServiceChainID at boot via this helper. Pure function — no global state mutated on call.

func SplitSecretPath

func SplitSecretPath(full string) (dir, name string)

SplitSecretPath turns "/foo/bar/baz" into ("/foo/bar/", "baz"). When there is no '/' or only a leading one, the directory is "" and the whole remainder is the name (e.g., "/mnemonic" → ("", "mnemonic")).

Exported so every consumer can address secrets with the same convention — one and only one addressing scheme across mnemonic, staking keys, gas-payer keys, etc.

func VerifyServiceEnvelope added in v1.0.10

func VerifyServiceEnvelope(pubKey []byte, fullDigest ids.FullDigest, envelope, sig []byte) error

VerifyServiceEnvelope verifies an ML-DSA-65 signature against an envelope produced by Sign. The caller supplies the signer's FullDigest (the 48-byte commitment carried in the envelope header) and public key bytes — both authenticated by the consensus layer.

Pure function: no I/O, no time dependency.

Types

type Allocation

type Allocation struct {
	// ETHAddr is the C-chain compatible address (0x...)
	ETHAddr string `json:"evmAddr"`

	// LUXAddr is the P/X-chain address (P-lux1...)
	LUXAddr string `json:"utxoAddr"`

	// InitialAmount is immediately available on X-chain (usually 0)
	InitialAmount uint64 `json:"initialAmount"`

	// UnlockSchedule defines when funds become available on P-chain
	UnlockSchedule []LockedAmount `json:"unlockSchedule"`
}

Allocation represents a P-chain genesis allocation

type AllocationBuilder

type AllocationBuilder struct {
	// contains filtered or unexported fields
}

AllocationBuilder helps build genesis allocations from validator keys

func NewAllocationBuilder

func NewAllocationBuilder(networkID uint32, keys []*ValidatorKey) *AllocationBuilder

NewAllocationBuilder creates a new builder for the given keys

func (*AllocationBuilder) Build

func (ab *AllocationBuilder) Build() (*GenesisAllocations, error)

Build creates the genesis allocations

func (*AllocationBuilder) WithAmount

func (ab *AllocationBuilder) WithAmount(amount uint64) *AllocationBuilder

WithAmount sets the amount per validator

func (*AllocationBuilder) WithFeeAccount

func (ab *AllocationBuilder) WithFeeAccount(index int, extra uint64) *AllocationBuilder

WithFeeAccount sets which validator gets extra funds for fees

func (*AllocationBuilder) WithImmediateUnlock

func (ab *AllocationBuilder) WithImmediateUnlock() *AllocationBuilder

WithImmediateUnlock makes funds immediately unlocked (locktime=0)

func (*AllocationBuilder) WithNoVesting

func (ab *AllocationBuilder) WithNoVesting() *AllocationBuilder

WithNoVesting makes all funds immediately available

func (*AllocationBuilder) WithVesting

func (ab *AllocationBuilder) WithVesting(start uint64, interval uint64, periods int) *AllocationBuilder

WithVesting configures the vesting schedule

type CChainAlloc

type CChainAlloc struct {
	Balance string `json:"balance"` // Hex-encoded wei amount
}

CChainAlloc represents a C-chain genesis allocation

type GenesisAllocations

type GenesisAllocations struct {
	// P-chain allocations
	PChainAllocations []Allocation `json:"allocations"`

	// Initial staked funds (addresses that are staked at genesis)
	InitialStakedFunds []string `json:"initialStakedFunds"`

	// Initial stakers (validators at genesis)
	InitialStakers []Staker `json:"initialStakers"`

	// C-chain allocations (address -> balance)
	CChainAllocations map[string]CChainAlloc `json:"cchain"`
}

GenesisAllocations contains all allocations for network genesis

func GenerateAndAllocate

func GenerateAndAllocate(keyStore *KeyStore, networkID uint32, count int, prefix string, amountPerKey uint64) (*GenesisAllocations, error)

GenerateAndAllocate generates keys and creates allocations in one step

func LoadAndAllocate

func LoadAndAllocate(keyStore *KeyStore, networkID uint32, amountPerKey uint64) (*GenesisAllocations, error)

LoadAndAllocate loads existing keys and creates allocations

func MainnetAllocations

func MainnetAllocations(networkID uint32, keys []*ValidatorKey) (*GenesisAllocations, error)

MainnetAllocations creates allocations suitable for mainnet (100-year vesting)

func QuickAllocations

func QuickAllocations(networkID uint32, keys []*ValidatorKey, amountPerKey uint64) (*GenesisAllocations, error)

QuickAllocations creates allocations with immediate unlock for testing

func TestnetAllocations

func TestnetAllocations(networkID uint32, keys []*ValidatorKey) (*GenesisAllocations, error)

TestnetAllocations creates allocations suitable for testnet (no vesting)

type HybridIdentity added in v1.1.0

type HybridIdentity struct {
	// ServicePath is the canonical path string (verbatim) used to
	// derive both hybrid components. Stored for diagnostics.
	ServicePath string

	// NodeID is the 20-byte canonical NodeID derived under
	// NodeIDSchemeMLDSA65 over the wire-form hybrid public key.
	NodeID ids.NodeID

	// TypedNodeID is the wire-form NodeID (scheme byte || NodeID).
	TypedNodeID ids.TypedNodeID

	// FullDigest is the 48-byte SHAKE256-384 commitment to the
	// hybrid identity. Bound into envelope signatures.
	FullDigest ids.FullDigest

	// PublicKey is the joint public key value. Both components are
	// always populated.
	PublicKey *HybridPublicKey

	// PublicKeyBytes is the canonical wire encoding of the joint
	// pubkey — useful for logging, storage, and on-chain commitment.
	// Same value HybridPublicKeyBytes(PublicKey) returns.
	PublicKeyBytes []byte
	// contains filtered or unexported fields
}

HybridIdentity binds a mnemonic-derived BBF-bound hybrid signing key (secp256k1 + ML-DSA-65) to its canonical NodeID. The struct owns the joint private key; call Wipe() when done.

The NodeID is committed to the wire-form joint pubkey via the existing ids.NodeIDSchemeMLDSA65 derivation — chosen because the PQ component is the binding primitive (an adversary that holds only the classical key cannot mint a NodeID's matching FullDigest). Per cryptographer review the single-SHAKE-256-384 derivation is sound; no BTC-style double-hash is added.

func DeriveHybridIdentity added in v1.1.0

func DeriveHybridIdentity(mnemonic, servicePath string) (*HybridIdentity, error)

DeriveHybridIdentity is the canonical constructor for a BBF-bound hybrid validator identity. mnemonic must be a valid BIP-39 phrase; servicePath must be non-empty. Returns the derived HybridIdentity ready to Sign().

Derivation tree:

classical: m/44' / 9000' / serviceIndex' / 0' / 0'   (secp256k1)
pq:        m/44' / 9000' / serviceIndex' / 0' / 1'   (ML-DSA-65)

The two leaves share the same hardened branches up to the role node; the only branch that distinguishes them is the leaf index (0 vs 1). Both leaves are hardened. The classical leaf at index 0 COINCIDES with the legacy ML-DSA-only service identity path — this is intentional: a hybrid identity is a superset that adds a PQ component, never a different tree position. The classical leaf is then KDF-mixed with HybridClassicalDomain so the secp256k1 scalar is cryptographically separated from any ML-DSA-only seed at the same BIP-32 leaf — they share the leaf but not the seed.

Pure function: given the same (mnemonic, servicePath) you get the same HybridIdentity, byte-for-byte. No I/O, no randomness, no clock reads.

func (*HybridIdentity) Sign added in v1.1.0

func (h *HybridIdentity) Sign(msg []byte) (*HybridSignature, error)

Sign produces a BBF-bound joint signature over msg. Delegates to HybridSign — the identity owns the joint private key.

func (*HybridIdentity) Wipe added in v1.1.0

func (h *HybridIdentity) Wipe()

Wipe zeroes the joint private key in place. Idempotent. Safe to call from a defer on a nil receiver.

type HybridPrivateKey added in v1.1.0

type HybridPrivateKey struct {
	// Classical is the secp256k1 signing key (32 bytes scalar).
	Classical *secp.PrivateKey

	// PQ is the ML-DSA-65 signing key (FIPS 204).
	PQ *mldsa.PrivateKey
}

HybridPrivateKey is the joint signing key of the BBF-bound hybrid scheme. Owns both private components; the only legal use is internal Sign(). Call Wipe() when done.

func (*HybridPrivateKey) Public added in v1.1.0

func (sk *HybridPrivateKey) Public() *HybridPublicKey

HybridPublic extracts the joint public key from the joint private key. Pure function: no allocation other than the returned struct.

func (*HybridPrivateKey) Wipe added in v1.1.0

func (sk *HybridPrivateKey) Wipe()

Wipe zeroes both private components in place. Idempotent. Safe to call from a defer on a nil receiver.

type HybridPublicKey added in v1.1.0

type HybridPublicKey struct {
	// Classical is the secp256k1 verification key. 33-byte compressed
	// SEC1 encoding on the wire. This is the same primitive the
	// existing Lux validator set uses for P/X identity.
	Classical *secp.PublicKey

	// PQ is the ML-DSA-65 verification key (FIPS 204). Bytes-on-the-
	// wire form is the standard ML-DSA-65 public key encoding.
	PQ *mldsa.PublicKey
}

HybridPublicKey is the joint pubkey of the BBF-bound hybrid scheme. Both components are required for any verification; a half-hybrid is a programmer error.

type HybridSignature added in v1.1.0

type HybridSignature struct {
	// Classical is the secp256k1 recoverable signature (65 bytes).
	Classical []byte

	// PQ is the ML-DSA-65 signature (FIPS 204 standard size).
	PQ []byte
}

HybridSignature is the joint signature of the BBF-bound hybrid scheme. BOTH components are required for verification. Neither is independently useful — that is the binding the scheme provides.

func HybridSign added in v1.1.0

func HybridSign(sk *HybridPrivateKey, msg []byte, randSource io.Reader) (*HybridSignature, error)

HybridSign produces a BBF-bound joint signature over msg under the given joint signing key. The classical signature uses secp256k1 SignHash over m_bound; the PQ signature uses ML-DSA-65 SignCtx with HybridSigDomain as the context.

Why two domain-separated bindings:

(1) m_bound's prefix binds the SHAKE256 input to this scheme.
(2) The ML-DSA context binds the FIPS 204 signature itself to
    this scheme — preventing cross-protocol replay of a future
    hybrid signature against any other ML-DSA-65 surface (KMS
    envelope, P-Chain block, etc.).

rand is the randomness source for ML-DSA-65 hedged signing. If nil, crypto/rand is used. The secp256k1 signature uses RFC 6979 deterministic-k — no randomness needed.

type KeyStore

type KeyStore struct {
	// contains filtered or unexported fields
}

KeyStore manages validator keys with filesystem persistence

func NewKeyStore

func NewKeyStore(baseDir string) *KeyStore

NewKeyStore creates a new key store at the given directory

func (*KeyStore) BaseDir

func (ks *KeyStore) BaseDir() string

BaseDir returns the base directory for the key store

func (*KeyStore) GenerateMultiple

func (ks *KeyStore) GenerateMultiple(count int, prefix string) ([]*ValidatorKey, error)

GenerateMultiple generates multiple validator keys

func (*KeyStore) List

func (ks *KeyStore) List() ([]string, error)

List returns all validator keys in the store

func (*KeyStore) Load

func (ks *KeyStore) Load(name string) (*ValidatorKey, error)

Load reads a validator key from the filesystem

func (*KeyStore) LoadAll

func (ks *KeyStore) LoadAll() ([]*ValidatorKey, error)

LoadAll loads all validator keys from the store

func (*KeyStore) Save

func (ks *KeyStore) Save(name string, vk *ValidatorKey) error

Save persists a validator key to the filesystem

type LockedAmount

type LockedAmount struct {
	Amount   uint64 `json:"amount"`
	Locktime uint64 `json:"locktime"`
}

LockedAmount represents a locked amount with unlock time

type MnemonicReader

type MnemonicReader interface {
	GetAt(ctx context.Context, path, name, env string) (string, error)
	Close()
}

MnemonicReader is the minimum surface LoadMnemonicFromKMS needs from a KMS client. The real *zapclient.Client satisfies it; tests inject fakes via the dialKMS seam below.

type ServiceIdentity added in v1.0.10

type ServiceIdentity struct {
	// ServicePath is the canonical path string (verbatim) used to derive
	// the BIP-32 hardened index. Stored for diagnostics; the
	// authoritative input is the derived NodeID.
	ServicePath string

	// NodeID is the 20-byte canonical NodeID derived under
	// NodeIDSchemeMLDSA65. Map-key safe.
	NodeID ids.NodeID

	// TypedNodeID is the wire-form NodeID (scheme byte || NodeID).
	// Travels in envelope headers so the receiver knows which verifier
	// to dispatch.
	TypedNodeID ids.TypedNodeID

	// FullDigest is the 48-byte SHAKE256-384 commitment to the
	// identity. Bound into envelope signatures to prevent cross-scheme
	// confusion attacks.
	FullDigest ids.FullDigest

	// PublicKey is the ML-DSA-65 public key bytes.
	PublicKey []byte
	// contains filtered or unexported fields
}

ServiceIdentity binds a mnemonic-derived ML-DSA-65 signing key to its canonical NodeID. The struct owns the private key bytes; call Wipe() when done.

Safe for concurrent use after construction — every field is read-only after NewServiceIdentity returns. Wipe is the only mutating method and the caller serialises it (typically a single defer).

func NewServiceIdentity added in v1.0.10

func NewServiceIdentity(mnemonic, servicePath string) (*ServiceIdentity, error)

NewServiceIdentity is the canonical constructor. mnemonic must be a valid BIP-39 phrase; servicePath must be non-empty. Returns the derived ServiceIdentity ready to Sign().

Pure function: given the same (mnemonic, servicePath) you get the same NodeID, byte-for-byte. No I/O, no randomness, no clock reads.

func (*ServiceIdentity) Sign added in v1.0.10

func (s *ServiceIdentity) Sign(envelope []byte) ([]byte, error)

Sign produces a deterministic ML-DSA-65 signature over the envelope digest. The caller is responsible for serialising the envelope into canonical bytes before calling Sign — see SignEnvelope for the canonical (method, path, payload, timestamp, nonce) shape.

The signed bytes are the SHAKE256 digest of:

left_encode(|domain|·8) || EnvelopeDomain ||
left_encode(|full_digest|·8) || FullDigest ||
left_encode(|envelope|·8) || envelope

Binding the FullDigest into the prehash means a verifier always rejects an envelope signed by a different identity — even a key with the same NodeID prefix.

func (*ServiceIdentity) Wipe added in v1.0.10

func (s *ServiceIdentity) Wipe()

Wipe zeroes the private key in place. Idempotent. Safe to call from a defer.

type Signer

type Signer struct {
	PublicKey         string `json:"publicKey"`
	ProofOfPossession string `json:"proofOfPossession"`
}

Signer contains BLS key information for a validator

type Staker

type Staker struct {
	NodeID        string  `json:"nodeID"`
	RewardAddress string  `json:"rewardAddress"`
	DelegationFee uint32  `json:"delegationFee"`
	Signer        *Signer `json:"signer,omitempty"`
}

Staker represents an initial validator in genesis

type ValidatorKey

type ValidatorKey struct {
	// NodeID is the unique identifier for the node (derived from TLS cert)
	NodeID ids.NodeID

	// TLS keys for node identity
	StakerKey  []byte // PEM-encoded private key
	StakerCert []byte // PEM-encoded certificate

	// BLS keys for consensus
	BLSSecretKey []byte // Raw BLS secret key bytes
	BLSPublicKey []byte // Compressed BLS public key
	BLSPoP       []byte // Proof of Possession signature

	// EC key for addresses
	ECPrivateKey []byte // Raw 32-byte secp256k1 private key

	// Derived addresses
	PChainAddr ids.ShortID // P/X chain address (20 bytes)
	CChainAddr ids.ShortID // C-chain address (20 bytes, Ethereum format)
}

ValidatorKey contains all keys needed for a validator node

func DeriveValidatorFromMnemonic

func DeriveValidatorFromMnemonic(mnemonic string, accountIndex uint32) (*ValidatorKey, error)

DeriveValidatorFromMnemonic derives a single validator key from mnemonic at given index. All keys (EC, TLS, BLS) are now derived deterministically from the mnemonic.

func DeriveValidatorsFromMnemonic

func DeriveValidatorsFromMnemonic(mnemonic string, count int) ([]*ValidatorKey, error)

DeriveValidatorsFromMnemonic derives N validator keys from a BIP39 mnemonic. Each validator uses BIP44 path m/44'/60'/0'/0/{index} for the EC key. TLS staking certs and BLS keys are generated fresh (not deterministic from mnemonic). This is designed for runtime use - no files are written to disk.

func GenerateValidatorKey

func GenerateValidatorKey() (*ValidatorKey, error)

GenerateValidatorKey creates a complete set of validator keys

func LoadFromDir

func LoadFromDir(nodeDir string) (*ValidatorKey, error)

LoadFromDir loads a validator key from a specific directory

func (*ValidatorKey) BLSKeyBase64

func (vk *ValidatorKey) BLSKeyBase64() string

BLSKeyBase64 returns the BLS secret key as base64 (for node config)

func (*ValidatorKey) BLSPoPHex

func (vk *ValidatorKey) BLSPoPHex() string

BLSPoPHex returns the BLS proof of possession as hex with 0x prefix

func (*ValidatorKey) BLSPublicKeyHex

func (vk *ValidatorKey) BLSPublicKeyHex() string

BLSPublicKeyHex returns the BLS public key as hex with 0x prefix

func (*ValidatorKey) CChainAddrHex

func (vk *ValidatorKey) CChainAddrHex() string

CChainAddrHex returns the C-chain address as hex with 0x prefix

Directories

Path Synopsis
cmd
keys command
Command keys manages validator keys for Lux networks.
Command keys manages validator keys for Lux networks.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL