Files
node/wallet/keychain/unified_keychain.go
zeekay 7cf87b230b node-unified is the node
The module already called itself github.com/luxfi/node while containing no node
in Go: cmd/luxd was twenty-one lines that printed the size of a few types, and
the Go column of the matrix measured a VM plugin. A repo that fetches the thing
it claims to be has not replaced it, so the Go sources move in — 1515 files,
the daemon and everything under it — and the build reaches outside this module
for nothing.

Rust and C++ sit beside it unchanged and are still measured against it by the
differential. That is the point of one repo: the reference implementation and
the two ports are the same checkout, so parity is a thing you can run rather
than a thing you assert.

Verified: builds, and the closure carries no lux-private — checked at build time
rather than believed. The daemon starts twelve chains on a local network
(P X C Q Z A B G K M F, plus D through its plugin) and reports healthy.
2026-09-07 16:15:25 -07:00

159 lines
4.3 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
//go:build ignore
package keychain
import (
"errors"
"github.com/luxfi/crypto"
"github.com/luxfi/ids"
"github.com/luxfi/math/set"
)
// UnifiedKeychain uses the unified crypto interface for all key operations
type UnifiedKeychain struct {
crypto crypto.UnifiedCrypto
keysByAddress map[ids.ShortID]*UnifiedSigner
addressSet set.Set[ids.ShortID]
defaultAlgo crypto.Algorithm
}
// NewUnifiedKeychain creates a new keychain using the unified crypto interface
func NewUnifiedKeychain(defaultAlgo crypto.Algorithm) *UnifiedKeychain {
return &UnifiedKeychain{
crypto: crypto.NewUnifiedCrypto(),
keysByAddress: make(map[ids.ShortID]*UnifiedSigner),
addressSet: set.NewSet[ids.ShortID](0),
defaultAlgo: defaultAlgo,
}
}
// GenerateKey generates a new key with the default algorithm
func (kc *UnifiedKeychain) GenerateKey() (ids.ShortID, error) {
privKey, pubKey, err := kc.crypto.GenerateKey(kc.defaultAlgo)
if err != nil {
return ids.ShortEmpty, err
}
return kc.AddKey(privKey, pubKey), nil
}
// GenerateKeyWithAlgo generates a new key with the specified algorithm
func (kc *UnifiedKeychain) GenerateKeyWithAlgo(algo crypto.Algorithm) (ids.ShortID, error) {
privKey, pubKey, err := kc.crypto.GenerateKey(algo)
if err != nil {
return ids.ShortEmpty, err
}
return kc.AddKey(privKey, pubKey), nil
}
// AddKey adds a key pair to the keychain
func (kc *UnifiedKeychain) AddKey(privKey crypto.PrivateKey, pubKey crypto.PublicKey) ids.ShortID {
addrBytes := pubKey.Address()
if len(addrBytes) < 20 {
// Pad if necessary
padded := make([]byte, 20)
copy(padded, addrBytes)
addrBytes = padded
}
addr := ids.ShortID{}
copy(addr[:], addrBytes[:20])
signer := &UnifiedSigner{
privKey: privKey,
pubKey: pubKey,
address: addr,
crypto: kc.crypto,
}
kc.keysByAddress[addr] = signer
kc.addressSet.Add(addr)
return addr
}
// Get returns the signer for the given address
func (kc *UnifiedKeychain) Get(addr ids.ShortID) (Signer, bool) {
signer, exists := kc.keysByAddress[addr]
if !exists {
return nil, false
}
return signer, true
}
// Addresses returns all addresses in the keychain
func (kc *UnifiedKeychain) Addresses() []ids.ShortID {
addrs := make([]ids.ShortID, 0, kc.addressSet.Len())
for addr := range kc.addressSet {
addrs = append(addrs, addr)
}
return addrs
}
// GetUnifiedSigner returns the unified signer for advanced operations
func (kc *UnifiedKeychain) GetUnifiedSigner(addr ids.ShortID) (*UnifiedSigner, bool) {
signer, exists := kc.keysByAddress[addr]
return signer, exists
}
// UnifiedSigner implements the Signer interface using unified crypto
type UnifiedSigner struct {
privKey crypto.PrivateKey
pubKey crypto.PublicKey
address ids.ShortID
crypto crypto.UnifiedCrypto
}
// Sign signs a message
func (s *UnifiedSigner) Sign(msg []byte) ([]byte, error) {
return s.crypto.Sign(s.privKey, msg)
}
// SignHash signs a hash (for compatibility)
func (s *UnifiedSigner) SignHash(hash []byte) ([]byte, error) {
// For algorithms that expect raw hashes
switch s.privKey.Algorithm() {
case crypto.AlgoSecp256k1:
// secp256k1 expects 32-byte hash
if len(hash) != 32 {
return nil, errors.New("invalid hash length for secp256k1")
}
}
return s.privKey.Sign(hash)
}
// Address returns the address
func (s *UnifiedSigner) Address() ids.ShortID {
return s.address
}
// Algorithm returns the algorithm used by this signer
func (s *UnifiedSigner) Algorithm() crypto.Algorithm {
return s.privKey.Algorithm()
}
// PublicKey returns the public key
func (s *UnifiedSigner) PublicKey() crypto.PublicKey {
return s.pubKey
}
// SignRing creates a ring signature (for privacy-preserving signatures)
func (s *UnifiedSigner) SignRing(message []byte, ring []crypto.PublicKey) ([]byte, error) {
return s.crypto.SignRing(s.privKey, message, ring)
}
// Encapsulate creates a ciphertext and shared secret (for ML-KEM)
func (s *UnifiedSigner) Encapsulate(pubKey crypto.PublicKey) (ciphertext []byte, sharedSecret []byte, err error) {
return s.crypto.Encapsulate(pubKey)
}
// Decapsulate recovers the shared secret from ciphertext (for ML-KEM)
func (s *UnifiedSigner) Decapsulate(ciphertext []byte) (sharedSecret []byte, err error) {
return s.crypto.Decapsulate(s.privKey, ciphertext)
}