mirror of
https://github.com/luxfi/keys.git
synced 2026-07-26 23:58:11 +00:00
fix: use standard BIP-44 coin type 60 for key derivation paths
This commit is contained in:
@@ -400,7 +400,7 @@ func (vk *ValidatorKey) CChainAddrHex() string {
|
||||
}
|
||||
|
||||
// DeriveValidatorsFromMnemonic derives N validator keys from a BIP39 mnemonic.
|
||||
// Each validator uses BIP44 path m/44'/9000'/0'/0/{index} for the EC key.
|
||||
// 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 DeriveValidatorsFromMnemonic(mnemonic string, count int) ([]*ValidatorKey, error) {
|
||||
@@ -426,7 +426,7 @@ func DeriveValidatorsFromMnemonic(mnemonic string, count int) ([]*ValidatorKey,
|
||||
func DeriveValidatorFromMnemonic(mnemonic string, accountIndex uint32) (*ValidatorKey, error) {
|
||||
vk := &ValidatorKey{}
|
||||
|
||||
// 1. Derive EC key from mnemonic using BIP44 path m/44'/9000'/0'/0/{index}
|
||||
// 1. Derive EC key from mnemonic using BIP44 path m/44'/60'/0'/0/{index}
|
||||
ecKeyBytes, err := deriveMnemonicKey(mnemonic, accountIndex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive EC key: %w", err)
|
||||
@@ -443,7 +443,7 @@ func DeriveValidatorFromMnemonic(mnemonic string, accountIndex uint32) (*Validat
|
||||
vk.CChainAddr = pubkeyToAddress(pubKey.ToECDSA())
|
||||
|
||||
// 2. Derive TLS staking cert deterministically from mnemonic
|
||||
// Use a separate derivation path: m/44'/9000'/1'/0/{index} for TLS keys
|
||||
// Use a separate derivation path: m/44'/60'/1'/0/{index} for TLS keys
|
||||
tlsKeyBytes, err := deriveMnemonicKeyForPath(mnemonic, 1, accountIndex) // account=1 for TLS
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive TLS key seed: %w", err)
|
||||
@@ -474,7 +474,7 @@ func DeriveValidatorFromMnemonic(mnemonic string, accountIndex uint32) (*Validat
|
||||
vk.NodeID = ids.NodeIDFromCert(stakingCert)
|
||||
|
||||
// 3. Derive BLS signer key deterministically from mnemonic
|
||||
// Use a separate derivation path: m/44'/9000'/2'/0/{index} for BLS keys
|
||||
// Use a separate derivation path: m/44'/60'/2'/0/{index} for BLS keys
|
||||
blsSeed, err := deriveMnemonicKeyForPath(mnemonic, 2, accountIndex) // account=2 for BLS
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive BLS key seed: %w", err)
|
||||
@@ -525,7 +525,7 @@ func deriveP256Key(seed []byte) (*ecdsa.PrivateKey, error) {
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
// deriveMnemonicKeyForPath derives a key using BIP44 path m/44'/9000'/{account}'/0/{index}
|
||||
// deriveMnemonicKeyForPath derives a key using BIP44 path m/44'/60'/{account}'/0/{index}
|
||||
func deriveMnemonicKeyForPath(mnemonic string, account, index uint32) ([]byte, error) {
|
||||
if !bip39.IsMnemonicValid(mnemonic) {
|
||||
return nil, fmt.Errorf("invalid mnemonic phrase")
|
||||
@@ -538,32 +538,32 @@ func deriveMnemonicKeyForPath(mnemonic string, account, index uint32) ([]byte, e
|
||||
return nil, fmt.Errorf("failed to create master key: %w", err)
|
||||
}
|
||||
|
||||
// BIP-44 path: m/44'/9000'/{account}'/0/{index}
|
||||
// BIP-44 path: m/44'/60'/{account}'/0/{index}
|
||||
// m/44' (purpose)
|
||||
key, err := masterKey.NewChildKey(bip32.FirstHardenedChild + 44)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive purpose: %w", err)
|
||||
}
|
||||
|
||||
// m/44'/9000' (coin type for LUX)
|
||||
// m/44'/60' (coin type for LUX)
|
||||
key, err = key.NewChildKey(bip32.FirstHardenedChild + LUXCoinType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive coin type: %w", err)
|
||||
}
|
||||
|
||||
// m/44'/9000'/{account}' (account - 0=EC, 1=TLS, 2=BLS)
|
||||
// m/44'/60'/{account}' (account - 0=EC, 1=TLS, 2=BLS)
|
||||
key, err = key.NewChildKey(bip32.FirstHardenedChild + account)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive account: %w", err)
|
||||
}
|
||||
|
||||
// m/44'/9000'/{account}'/0 (change)
|
||||
// m/44'/60'/{account}'/0 (change)
|
||||
key, err = key.NewChildKey(0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive change: %w", err)
|
||||
}
|
||||
|
||||
// m/44'/9000'/{account}'/0/{index} (address index)
|
||||
// m/44'/60'/{account}'/0/{index} (address index)
|
||||
key, err = key.NewChildKey(index)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive address index: %w", err)
|
||||
@@ -572,10 +572,10 @@ func deriveMnemonicKeyForPath(mnemonic string, account, index uint32) ([]byte, e
|
||||
return key.Key, nil
|
||||
}
|
||||
|
||||
// LUXCoinType is the BIP-44 coin type for LUX (9000')
|
||||
const LUXCoinType = 9000
|
||||
// LUXCoinType is the BIP-44 coin type for LUX (60' = standard Ethereum)
|
||||
const LUXCoinType = 60
|
||||
|
||||
// deriveMnemonicKey derives an EC private key from mnemonic using BIP44 path m/44'/9000'/0'/0/{index}
|
||||
// deriveMnemonicKey derives an EC private key from mnemonic using BIP44 path m/44'/60'/0'/0/{index}
|
||||
func deriveMnemonicKey(mnemonic string, accountIndex uint32) ([]byte, error) {
|
||||
if !bip39.IsMnemonicValid(mnemonic) {
|
||||
return nil, fmt.Errorf("invalid mnemonic phrase")
|
||||
@@ -588,32 +588,32 @@ func deriveMnemonicKey(mnemonic string, accountIndex uint32) ([]byte, error) {
|
||||
return nil, fmt.Errorf("failed to create master key: %w", err)
|
||||
}
|
||||
|
||||
// BIP-44 path: m/44'/9000'/0'/0/{accountIndex}
|
||||
// BIP-44 path: m/44'/60'/0'/0/{accountIndex}
|
||||
// m/44' (purpose)
|
||||
key, err := masterKey.NewChildKey(bip32.FirstHardenedChild + 44)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive purpose: %w", err)
|
||||
}
|
||||
|
||||
// m/44'/9000' (coin type for LUX)
|
||||
// m/44'/60' (coin type for LUX)
|
||||
key, err = key.NewChildKey(bip32.FirstHardenedChild + LUXCoinType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive coin type: %w", err)
|
||||
}
|
||||
|
||||
// m/44'/9000'/0' (account)
|
||||
// m/44'/60'/0' (account)
|
||||
key, err = key.NewChildKey(bip32.FirstHardenedChild + 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive account: %w", err)
|
||||
}
|
||||
|
||||
// m/44'/9000'/0'/0 (change)
|
||||
// m/44'/60'/0'/0 (change)
|
||||
key, err = key.NewChildKey(0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive change: %w", err)
|
||||
}
|
||||
|
||||
// m/44'/9000'/0'/0/{accountIndex} (address index)
|
||||
// m/44'/60'/0'/0/{accountIndex} (address index)
|
||||
key, err = key.NewChildKey(accountIndex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to derive address index: %w", err)
|
||||
|
||||
Reference in New Issue
Block a user