lnd.xprv/keychain/derivation.go
2020-09-17 10:14:54 +08:00

251 lines
10 KiB
Go

package keychain
import (
"fmt"
"github.com/btcsuite/btcd/btcec"
)
const (
// KeyDerivationVersion is the version of the key derivation schema
// defined below. We use a version as this means that we'll be able to
// accept new seed in the future and be able to discern if the software
// is compatible with the version of the seed.
KeyDerivationVersion = 0
// BIP0043Purpose is the "purpose" value that we'll use for the first
// version or our key derivation scheme. All keys are expected to be
// derived from this purpose, then the particular coin type of the
// chain where the keys are to be used. Slightly adhering to BIP0043
// allows us to not deviate too far from a widely used standard, and
// also fits into existing implementations of the BIP's template.
//
// NOTE: BRICK SQUUUUUAD.
BIP0043Purpose = 1017
)
var (
// MaxKeyRangeScan is the maximum number of keys that we'll attempt to
// scan with if a caller knows the public key, but not the KeyLocator
// and wishes to derive a private key.
MaxKeyRangeScan = 100000
// ErrCannotDerivePrivKey is returned when DerivePrivKey is unable to
// derive a private key given only the public key and target key
// family.
ErrCannotDerivePrivKey = fmt.Errorf("unable to derive private key")
)
// KeyFamily represents a "family" of keys that will be used within various
// contracts created by lnd. These families are meant to be distinct branches
// within the HD key chain of the backing wallet. Usage of key families within
// the interface below are strict in order to promote integrability and the
// ability to restore all keys given a user master seed backup.
//
// The key derivation in this file follows the following hierarchy based on
// BIP43:
//
// * m/1017'/coinType'/keyFamily'/0/index
type KeyFamily uint32
const (
// KeyFamilyMultiSig are keys to be used within multi-sig scripts.
KeyFamilyMultiSig KeyFamily = 0
// KeyFamilyRevocationBase are keys that are used within channels to
// create revocation basepoints that the remote party will use to
// create revocation keys for us.
KeyFamilyRevocationBase KeyFamily = 1
// KeyFamilyHtlcBase are keys used within channels that will be
// combined with per-state randomness to produce public keys that will
// be used in HTLC scripts.
KeyFamilyHtlcBase KeyFamily = 2
// KeyFamilyPaymentBase are keys used within channels that will be
// combined with per-state randomness to produce public keys that will
// be used in scripts that pay directly to us without any delay.
KeyFamilyPaymentBase KeyFamily = 3
// KeyFamilyDelayBase are keys used within channels that will be
// combined with per-state randomness to produce public keys that will
// be used in scripts that pay to us, but require a CSV delay before we
// can sweep the funds.
KeyFamilyDelayBase KeyFamily = 4
// KeyFamilyRevocationRoot is a family of keys which will be used to
// derive the root of a revocation tree for a particular channel.
KeyFamilyRevocationRoot KeyFamily = 5
// KeyFamilyNodeKey is a family of keys that will be used to derive
// keys that will be advertised on the network to represent our current
// "identity" within the network. Peers will need our latest node key
// in order to establish a transport session with us on the Lightning
// p2p level (BOLT-0008).
KeyFamilyNodeKey KeyFamily = 6
// KeyFamilyStaticBackup is the family of keys that will be used to
// derive keys that we use to encrypt and decrypt our set of static
// backups. These backups may either be stored within watch towers for
// a payment, or self stored on disk in a single file containing all
// the static channel backups.
KeyFamilyStaticBackup KeyFamily = 7
// KeyFamilyTowerSession is the family of keys that will be used to
// derive session keys when negotiating sessions with watchtowers. The
// session keys are limited to the lifetime of the session and are used
// to increase privacy in the watchtower protocol.
KeyFamilyTowerSession KeyFamily = 8
// KeyFamilyTowerID is the family of keys used to derive the public key
// of a watchtower. This made distinct from the node key to offer a form
// of rudimentary whitelisting, i.e. via knowledge of the pubkey,
// preventing others from having full access to the tower just as a
// result of knowing the node key.
KeyFamilyTowerID KeyFamily = 9
)
// KeyLocator is a two-tuple that can be used to derive *any* key that has ever
// been used under the key derivation mechanisms described in this file.
// Version 0 of our key derivation schema uses the following BIP43-like
// derivation:
//
// * m/1017'/coinType'/keyFamily'/0/index
//
// Our purpose is 1017 (chosen arbitrary for now), and the coin type will vary
// based on which coin/chain the channels are being created on. The key family
// are actually just individual "accounts" in the nomenclature of BIP43. By
// default we assume a branch of 0 (external). Finally, the key index (which
// will vary per channel and use case) is the final element which allows us to
// deterministically derive keys.
type KeyLocator struct {
// TODO(roasbeef): add the key scope as well??
// Family is the family of key being identified.
Family KeyFamily
// Index is the precise index of the key being identified.
Index uint32
}
// IsEmpty returns true if a KeyLocator is "empty". This may be the case where
// we learn of a key from a remote party for a contract, but don't know the
// precise details of its derivation (as we don't know the private key!).
func (k KeyLocator) IsEmpty() bool {
return k.Family == 0 && k.Index == 0
}
// KeyDescriptor wraps a KeyLocator and also optionally includes a public key.
// Either the KeyLocator must be non-empty, or the public key pointer be
// non-nil. This will be used by the KeyRing interface to lookup arbitrary
// private keys, and also within the SignDescriptor struct to locate precisely
// which keys should be used for signing.
type KeyDescriptor struct {
// KeyLocator is the internal KeyLocator of the descriptor.
KeyLocator
// PubKey is an optional public key that fully describes a target key.
// If this is nil, the KeyLocator MUST NOT be empty.
PubKey *btcec.PublicKey
}
// KeyRing is the primary interface that will be used to perform public
// derivation of various keys used within the peer-to-peer network, and also
// within any created contracts. All derivation required by the KeyRing is
// based off of public derivation, so a system with only an extended public key
// (for the particular purpose+family) can derive this set of keys.
type KeyRing interface {
// DeriveNextKey attempts to derive the *next* key within the key
// family (account in BIP43) specified. This method should return the
// next external child within this branch.
DeriveNextKey(keyFam KeyFamily) (KeyDescriptor, error)
// DeriveKey attempts to derive an arbitrary key specified by the
// passed KeyLocator. This may be used in several recovery scenarios,
// or when manually rotating something like our current default node
// key.
DeriveKey(keyLoc KeyLocator) (KeyDescriptor, error)
}
// SecretKeyRing is a ring similar to the regular KeyRing interface, but it is
// also able to derive *private keys*. As this is a super-set of the regular
// KeyRing, we also expect the SecretKeyRing to implement the fully KeyRing
// interface. The methods in this struct may be used to extract the node key in
// order to accept inbound network connections, or to do manual signing for
// recovery purposes.
type SecretKeyRing interface {
KeyRing
ECDHRing
DigestSignerRing
// DerivePrivKey attempts to derive the private key that corresponds to
// the passed key descriptor. If the public key is set, then this
// method will perform an in-order scan over the key set, with a max of
// MaxKeyRangeScan keys. In order for this to work, the caller MUST set
// the KeyFamily within the partially populated KeyLocator.
DerivePrivKey(keyDesc KeyDescriptor) (*btcec.PrivateKey, error)
}
// DigestSignerRing is an interface that abstracts away basic low-level ECDSA
// signing on keys within a key ring.
type DigestSignerRing interface {
// SignDigest signs the given SHA256 message digest with the private key
// described in the key descriptor.
SignDigest(keyDesc KeyDescriptor, digest [32]byte) (*btcec.Signature,
error)
// SignDigestCompact signs the given SHA256 message digest with the
// private key described in the key descriptor and returns the signature
// in the compact, public key recoverable format.
SignDigestCompact(keyDesc KeyDescriptor, digest [32]byte) ([]byte, error)
}
// SingleKeyDigestSigner is an abstraction interface that hides the
// implementation of the low-level ECDSA signing operations by wrapping a
// single, specific private key.
type SingleKeyDigestSigner interface {
// PubKey returns the public key of the wrapped private key.
PubKey() *btcec.PublicKey
// SignDigest signs the given SHA256 message digest with the wrapped
// private key.
SignDigest(digest [32]byte) (*btcec.Signature, error)
// SignDigestCompact signs the given SHA256 message digest with the
// wrapped private key and returns the signature in the compact, public
// key recoverable format.
SignDigestCompact(digest [32]byte) ([]byte, error)
}
// ECDHRing is an interface that abstracts away basic low-level ECDH shared key
// generation on keys within a key ring.
type ECDHRing interface {
// ECDH performs a scalar multiplication (ECDH-like operation) between
// the target key descriptor and remote public key. The output
// returned will be the sha256 of the resulting shared point serialized
// in compressed format. If k is our private key, and P is the public
// key, we perform the following operation:
//
// sx := k*P
// s := sha256(sx.SerializeCompressed())
ECDH(keyDesc KeyDescriptor, pubKey *btcec.PublicKey) ([32]byte, error)
}
// SingleKeyECDH is an abstraction interface that hides the implementation of an
// ECDH operation by wrapping a single, specific private key.
type SingleKeyECDH interface {
// PubKey returns the public key of the wrapped private key.
PubKey() *btcec.PublicKey
// ECDH performs a scalar multiplication (ECDH-like operation) between
// the wrapped private key and remote public key. The output returned
// will be the sha256 of the resulting shared point serialized in
// compressed format.
ECDH(pubKey *btcec.PublicKey) ([32]byte, error)
}
// TODO(roasbeef): extend to actually support scalar mult of key?
// * would allow to push in initial handshake auth into interface as well