Update golangci-lint to v2.12.2 with canonical config
All checks were successful
check / check (push) Successful in 1m8s
All checks were successful
check / check (push) Successful in 1m8s
- Replace .golangci.yml with the canonical strict config (all linters enabled except the standard disable list; lll 88, funlen 80/50, cyclop 15, dupl 100; test files now linted) - Pin the Dockerfile lint stage to golangci/golangci-lint:v2.12.2 by tag and digest (Debian-based) - Fix all ~1550 findings surfaced by the new config: line wrapping, wsl_v5/nlreturn blank lines, noinlineerr splits, err113 sentinel errors, perfsprint/modernize rewrites, goconst constants, thelper, testifylint, noctx CommandContext, testpackage conversions, t.Parallel() where safe, and complexity/dupl helper extraction - Record the change and follow-up items in TODO.md
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
@@ -23,10 +24,10 @@ import (
|
||||
|
||||
const (
|
||||
// BIP85_MASTER_PATH is the derivation path prefix for all BIP85 applications
|
||||
BIP85_MASTER_PATH = "m/83696968'" //nolint:revive // ALL_CAPS used for BIP85 constants
|
||||
BIP85_MASTER_PATH = "m/83696968'" //nolint:revive // BIP85 spec naming
|
||||
|
||||
// BIP85_KEY_HMAC_KEY is the HMAC key used for deriving the entropy
|
||||
BIP85_KEY_HMAC_KEY = "bip-entropy-from-k" //nolint:revive // ALL_CAPS used for BIP85 constants
|
||||
BIP85_KEY_HMAC_KEY = "bip-entropy-from-k" //nolint:revive // BIP85 spec naming
|
||||
|
||||
// AppBIP39 is the application number for BIP39 mnemonics
|
||||
AppBIP39 = 39
|
||||
@@ -34,18 +35,43 @@ const (
|
||||
AppHDWIF = 2
|
||||
// AppXPRV is the application number for extended private key
|
||||
AppXPRV = 32
|
||||
APP_HEX = 128169 //nolint:revive // ALL_CAPS used for BIP85 constants
|
||||
APP_PWD64 = 707764 // Base64 passwords //nolint:revive // ALL_CAPS used for BIP85 constants
|
||||
APP_HEX = 128169 //nolint:revive // BIP85 spec naming
|
||||
APP_PWD64 = 707764 // Base64 passwords //nolint:revive // BIP85 spec naming
|
||||
AppPWD85 = 707785 // Base85 passwords
|
||||
APP_RSA = 828365 //nolint:revive // ALL_CAPS used for BIP85 constants
|
||||
APP_RSA = 828365 //nolint:revive // BIP85 spec naming
|
||||
)
|
||||
|
||||
// Sentinel errors for BIP85 derivation.
|
||||
var (
|
||||
// ErrNotPrivateKey is returned when the supplied master key is not a
|
||||
// private key.
|
||||
ErrNotPrivateKey = errors.New("master key must be a private key")
|
||||
// ErrInvalidPathComponent is returned when a derivation path component
|
||||
// cannot be parsed.
|
||||
ErrInvalidPathComponent = errors.New("invalid path component")
|
||||
// ErrInvalidWordCount is returned for unsupported BIP39 word counts.
|
||||
ErrInvalidWordCount = errors.New("invalid BIP39 word count")
|
||||
// ErrInvalidNumBytes is returned when numBytes is out of range.
|
||||
ErrInvalidNumBytes = errors.New("numBytes must be between 16 and 64")
|
||||
// ErrInvalidBase64PwdLen is returned when the Base64 password length
|
||||
// is out of range.
|
||||
ErrInvalidBase64PwdLen = errors.New("pwdLen must be between 20 and 86")
|
||||
// ErrInvalidBase85PwdLen is returned when the Base85 password length
|
||||
// is out of range.
|
||||
ErrInvalidBase85PwdLen = errors.New("pwdLen must be between 10 and 80")
|
||||
// ErrPasswordTooShort is returned when the derived material is
|
||||
// shorter than the requested password length.
|
||||
ErrPasswordTooShort = errors.New("derived password too short")
|
||||
)
|
||||
|
||||
// Version bytes for extended keys
|
||||
//
|
||||
//nolint:gochecknoglobals // standard BIP32 version constants
|
||||
var (
|
||||
// MainNetPrivateKey is the version for mainnet private keys
|
||||
MainNetPrivateKey = []byte{0x04, 0x88, 0xAD, 0xE4} //nolint:gochecknoglobals // Standard BIP32 constant
|
||||
MainNetPrivateKey = []byte{0x04, 0x88, 0xAD, 0xE4}
|
||||
// TestNetPrivateKey is the version for testnet private keys
|
||||
TestNetPrivateKey = []byte{0x04, 0x35, 0x83, 0x94} //nolint:gochecknoglobals // Standard BIP32 constant
|
||||
TestNetPrivateKey = []byte{0x04, 0x35, 0x83, 0x94}
|
||||
)
|
||||
|
||||
// DRNG is a deterministic random number generator seeded by BIP85 entropy
|
||||
@@ -71,7 +97,7 @@ func NewBIP85DRNG(entropy []byte) *DRNG {
|
||||
}
|
||||
|
||||
// Read implements the io.Reader interface
|
||||
func (d *DRNG) Read(p []byte) (n int, err error) {
|
||||
func (d *DRNG) Read(p []byte) (int, error) {
|
||||
return d.shake.Read(p)
|
||||
}
|
||||
|
||||
@@ -79,7 +105,7 @@ func (d *DRNG) Read(p []byte) (n int, err error) {
|
||||
func DeriveChildKey(masterKey *hdkeychain.ExtendedKey, path string) ([]byte, error) {
|
||||
// Validate the masterKey is a private key
|
||||
if !masterKey.IsPrivate() {
|
||||
return nil, fmt.Errorf("master key must be a private key")
|
||||
return nil, ErrNotPrivateKey
|
||||
}
|
||||
|
||||
// Derive the child key at the specified path
|
||||
@@ -98,8 +124,12 @@ func DeriveChildKey(masterKey *hdkeychain.ExtendedKey, path string) ([]byte, err
|
||||
return ecPrivKey.Serialize(), nil
|
||||
}
|
||||
|
||||
// DeriveBIP85Entropy derives entropy from a BIP32 master key using the BIP85 method
|
||||
func DeriveBIP85Entropy(masterKey *hdkeychain.ExtendedKey, path string) ([]byte, error) {
|
||||
// DeriveBIP85Entropy derives entropy from a BIP32 master key using the
|
||||
// BIP85 method
|
||||
func DeriveBIP85Entropy(
|
||||
masterKey *hdkeychain.ExtendedKey,
|
||||
path string,
|
||||
) ([]byte, error) {
|
||||
// Get the child key bytes
|
||||
privKeyBytes, err := DeriveChildKey(masterKey, path)
|
||||
if err != nil {
|
||||
@@ -115,7 +145,10 @@ func DeriveBIP85Entropy(masterKey *hdkeychain.ExtendedKey, path string) ([]byte,
|
||||
}
|
||||
|
||||
// deriveChildKey derives a child key from a parent key using the given path
|
||||
func deriveChildKey(parent *hdkeychain.ExtendedKey, path string) (*hdkeychain.ExtendedKey, error) {
|
||||
func deriveChildKey(
|
||||
parent *hdkeychain.ExtendedKey,
|
||||
path string,
|
||||
) (*hdkeychain.ExtendedKey, error) {
|
||||
if path == "" || path == "m" || path == "/" {
|
||||
return parent, nil
|
||||
}
|
||||
@@ -141,9 +174,12 @@ func deriveChildKey(parent *hdkeychain.ExtendedKey, path string) (*hdkeychain.Ex
|
||||
|
||||
// Parse the index
|
||||
var index uint32
|
||||
|
||||
_, err := fmt.Sscanf(component, "%d", &index)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid path component: %s", component)
|
||||
return nil, fmt.Errorf(
|
||||
"%w: %s", ErrInvalidPathComponent, component,
|
||||
)
|
||||
}
|
||||
|
||||
// Apply hardening if needed
|
||||
@@ -164,8 +200,14 @@ func deriveChildKey(parent *hdkeychain.ExtendedKey, path string) (*hdkeychain.Ex
|
||||
}
|
||||
|
||||
// DeriveBIP39Entropy derives entropy for a BIP39 mnemonic
|
||||
func DeriveBIP39Entropy(masterKey *hdkeychain.ExtendedKey, language, words, index uint32) ([]byte, error) {
|
||||
path := fmt.Sprintf("%s/%d'/%d'/%d'/%d'", BIP85_MASTER_PATH, AppBIP39, language, words, index)
|
||||
func DeriveBIP39Entropy(
|
||||
masterKey *hdkeychain.ExtendedKey,
|
||||
language, words, index uint32,
|
||||
) ([]byte, error) {
|
||||
path := fmt.Sprintf(
|
||||
"%s/%d'/%d'/%d'/%d'",
|
||||
BIP85_MASTER_PATH, AppBIP39, language, words, index,
|
||||
)
|
||||
|
||||
entropy, err := DeriveBIP85Entropy(masterKey, path)
|
||||
if err != nil {
|
||||
@@ -183,6 +225,7 @@ func DeriveBIP39Entropy(masterKey *hdkeychain.ExtendedKey, language, words, inde
|
||||
)
|
||||
|
||||
var bits int
|
||||
|
||||
switch words {
|
||||
case words12:
|
||||
bits = 128
|
||||
@@ -195,7 +238,7 @@ func DeriveBIP39Entropy(masterKey *hdkeychain.ExtendedKey, language, words, inde
|
||||
case words24:
|
||||
bits = 256
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid BIP39 word count: %d", words)
|
||||
return nil, fmt.Errorf("%w: %d", ErrInvalidWordCount, words)
|
||||
}
|
||||
|
||||
// Truncate to the required number of bits (bytes = bits / 8)
|
||||
@@ -218,6 +261,7 @@ func DeriveWIFKey(masterKey *hdkeychain.ExtendedKey, index uint32) (string, erro
|
||||
|
||||
// Convert to WIF format
|
||||
privKey, _ := btcec.PrivKeyFromBytes(keyBytes)
|
||||
|
||||
wif, err := btcutil.NewWIF(privKey, &chaincfg.MainNetParams, true) // compressed=true
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create WIF: %w", err)
|
||||
@@ -227,7 +271,10 @@ func DeriveWIFKey(masterKey *hdkeychain.ExtendedKey, index uint32) (string, erro
|
||||
}
|
||||
|
||||
// DeriveXPRV derives an extended private key (XPRV)
|
||||
func DeriveXPRV(masterKey *hdkeychain.ExtendedKey, index uint32) (*hdkeychain.ExtendedKey, error) {
|
||||
func DeriveXPRV(
|
||||
masterKey *hdkeychain.ExtendedKey,
|
||||
index uint32,
|
||||
) (*hdkeychain.ExtendedKey, error) {
|
||||
path := fmt.Sprintf("%s/%d'/%d'", BIP85_MASTER_PATH, AppXPRV, index)
|
||||
|
||||
entropy, err := DeriveBIP85Entropy(masterKey, path)
|
||||
@@ -266,10 +313,10 @@ func DeriveXPRV(masterKey *hdkeychain.ExtendedKey, index uint32) (*hdkeychain.Ex
|
||||
checksum := doubleSHA256(serializedBytes)[:4]
|
||||
|
||||
// Append checksum
|
||||
serializedWithChecksum := append(serializedBytes, checksum...)
|
||||
serializedBytes = append(serializedBytes, checksum...)
|
||||
|
||||
// Base58 encode
|
||||
xprvStr := base58.Encode(serializedWithChecksum)
|
||||
xprvStr := base58.Encode(serializedBytes)
|
||||
|
||||
// Parse the serialized xprv back to an ExtendedKey
|
||||
return hdkeychain.NewKeyFromString(xprvStr)
|
||||
@@ -284,9 +331,12 @@ func doubleSHA256(data []byte) []byte {
|
||||
}
|
||||
|
||||
// DeriveHex derives a raw hex string of specified length
|
||||
func DeriveHex(masterKey *hdkeychain.ExtendedKey, numBytes, index uint32) (string, error) {
|
||||
func DeriveHex(
|
||||
masterKey *hdkeychain.ExtendedKey,
|
||||
numBytes, index uint32,
|
||||
) (string, error) {
|
||||
if numBytes < 16 || numBytes > 64 {
|
||||
return "", fmt.Errorf("numBytes must be between 16 and 64")
|
||||
return "", ErrInvalidNumBytes
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/%d'/%d'/%d'", BIP85_MASTER_PATH, APP_HEX, numBytes, index)
|
||||
@@ -303,9 +353,12 @@ func DeriveHex(masterKey *hdkeychain.ExtendedKey, numBytes, index uint32) (strin
|
||||
}
|
||||
|
||||
// DeriveBase64Password derives a password encoded in Base64
|
||||
func DeriveBase64Password(masterKey *hdkeychain.ExtendedKey, pwdLen, index uint32) (string, error) {
|
||||
func DeriveBase64Password(
|
||||
masterKey *hdkeychain.ExtendedKey,
|
||||
pwdLen, index uint32,
|
||||
) (string, error) {
|
||||
if pwdLen < 20 || pwdLen > 86 {
|
||||
return "", fmt.Errorf("pwdLen must be between 20 and 86")
|
||||
return "", ErrInvalidBase64PwdLen
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/%d'/%d'/%d'", BIP85_MASTER_PATH, APP_PWD64, pwdLen, index)
|
||||
@@ -323,16 +376,22 @@ func DeriveBase64Password(masterKey *hdkeychain.ExtendedKey, pwdLen, index uint3
|
||||
|
||||
// Slice to the desired password length
|
||||
if len(encodedStr) < int(pwdLen) {
|
||||
return "", fmt.Errorf("derived password length %d is shorter than requested length %d", len(encodedStr), pwdLen)
|
||||
return "", fmt.Errorf(
|
||||
"%w: derived length %d is shorter than requested length %d",
|
||||
ErrPasswordTooShort, len(encodedStr), pwdLen,
|
||||
)
|
||||
}
|
||||
|
||||
return encodedStr[:pwdLen], nil
|
||||
}
|
||||
|
||||
// DeriveBase85Password derives a password encoded in Base85
|
||||
func DeriveBase85Password(masterKey *hdkeychain.ExtendedKey, pwdLen, index uint32) (string, error) {
|
||||
func DeriveBase85Password(
|
||||
masterKey *hdkeychain.ExtendedKey,
|
||||
pwdLen, index uint32,
|
||||
) (string, error) {
|
||||
if pwdLen < 10 || pwdLen > 80 {
|
||||
return "", fmt.Errorf("pwdLen must be between 10 and 80")
|
||||
return "", ErrInvalidBase85PwdLen
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/%d'/%d'/%d'", BIP85_MASTER_PATH, AppPWD85, pwdLen, index)
|
||||
@@ -347,16 +406,21 @@ func DeriveBase85Password(masterKey *hdkeychain.ExtendedKey, pwdLen, index uint3
|
||||
|
||||
// Slice to the desired password length
|
||||
if len(encoded) < int(pwdLen) {
|
||||
return "", fmt.Errorf("encoded length %d is less than requested length %d", len(encoded), pwdLen)
|
||||
return "", fmt.Errorf(
|
||||
"%w: encoded length %d is less than requested length %d",
|
||||
ErrPasswordTooShort, len(encoded), pwdLen,
|
||||
)
|
||||
}
|
||||
|
||||
return encoded[:pwdLen], nil
|
||||
}
|
||||
|
||||
// encodeBase85WithRFC1924Charset encodes data using Base85 with the RFC1924 character set
|
||||
// encodeBase85WithRFC1924Charset encodes data using Base85 with the
|
||||
// RFC1924 character set
|
||||
func encodeBase85WithRFC1924Charset(data []byte) string {
|
||||
// RFC1924 character set
|
||||
charset := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
|
||||
charset := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
|
||||
"abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
|
||||
|
||||
const (
|
||||
base85ChunkSize = 4 // Process 4 bytes at a time
|
||||
@@ -369,7 +433,9 @@ func encodeBase85WithRFC1924Charset(data []byte) string {
|
||||
copy(padded, data)
|
||||
|
||||
var buf strings.Builder
|
||||
buf.Grow(len(padded) * base85DigitCount / base85ChunkSize) // Each 4 bytes becomes 5 Base85 characters
|
||||
|
||||
// Each 4 bytes becomes 5 Base85 characters
|
||||
buf.Grow(len(padded) * base85DigitCount / base85ChunkSize)
|
||||
|
||||
// Process in 4-byte chunks
|
||||
for i := 0; i < len(padded); i += base85ChunkSize {
|
||||
|
||||
Reference in New Issue
Block a user