Merge pull request #4227 from guggero/signing-abstraction
multi: Remove need for DerivePrivKey from watchtower, brontide, netann and sphinx package
This commit is contained in:
commit
64b8aa8f11
@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,8 +33,9 @@ var _ net.Conn = (*Conn)(nil)
|
|||||||
// remote peer located at address which has remotePub as its long-term static
|
// remote peer located at address which has remotePub as its long-term static
|
||||||
// public key. In the case of a handshake failure, the connection is closed and
|
// public key. In the case of a handshake failure, the connection is closed and
|
||||||
// a non-nil error is returned.
|
// a non-nil error is returned.
|
||||||
func Dial(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress,
|
func Dial(local keychain.SingleKeyECDH, netAddr *lnwire.NetAddress,
|
||||||
dialer func(string, string) (net.Conn, error)) (*Conn, error) {
|
dialer func(string, string) (net.Conn, error)) (*Conn, error) {
|
||||||
|
|
||||||
ipAddr := netAddr.Address.String()
|
ipAddr := netAddr.Address.String()
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var err error
|
var err error
|
||||||
@ -44,7 +46,7 @@ func Dial(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress,
|
|||||||
|
|
||||||
b := &Conn{
|
b := &Conn{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
noise: NewBrontideMachine(true, localPriv, netAddr.IdentityKey),
|
noise: NewBrontideMachine(true, local, netAddr.IdentityKey),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initiate the handshake by sending the first act to the receiver.
|
// Initiate the handshake by sending the first act to the receiver.
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
)
|
)
|
||||||
|
|
||||||
// defaultHandshakes is the maximum number of handshakes that can be done in
|
// defaultHandshakes is the maximum number of handshakes that can be done in
|
||||||
@ -20,7 +20,7 @@ const defaultHandshakes = 1000
|
|||||||
// details w.r.t the handshake and encryption scheme used within the
|
// details w.r.t the handshake and encryption scheme used within the
|
||||||
// connection.
|
// connection.
|
||||||
type Listener struct {
|
type Listener struct {
|
||||||
localStatic *btcec.PrivateKey
|
localStatic keychain.SingleKeyECDH
|
||||||
|
|
||||||
tcp *net.TCPListener
|
tcp *net.TCPListener
|
||||||
|
|
||||||
@ -34,8 +34,9 @@ var _ net.Listener = (*Listener)(nil)
|
|||||||
|
|
||||||
// NewListener returns a new net.Listener which enforces the Brontide scheme
|
// NewListener returns a new net.Listener which enforces the Brontide scheme
|
||||||
// during both initial connection establishment and data transfer.
|
// during both initial connection establishment and data transfer.
|
||||||
func NewListener(localStatic *btcec.PrivateKey, listenAddr string) (*Listener,
|
func NewListener(localStatic keychain.SingleKeyECDH,
|
||||||
error) {
|
listenAddr string) (*Listener, error) {
|
||||||
|
|
||||||
addr, err := net.ResolveTCPAddr("tcp", listenAddr)
|
addr, err := net.ResolveTCPAddr("tcp", listenAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"golang.org/x/crypto/hkdf"
|
"golang.org/x/crypto/hkdf"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -71,14 +72,9 @@ var (
|
|||||||
|
|
||||||
// ecdh performs an ECDH operation between pub and priv. The returned value is
|
// ecdh performs an ECDH operation between pub and priv. The returned value is
|
||||||
// the sha256 of the compressed shared point.
|
// the sha256 of the compressed shared point.
|
||||||
func ecdh(pub *btcec.PublicKey, priv *btcec.PrivateKey) []byte {
|
func ecdh(pub *btcec.PublicKey, priv keychain.SingleKeyECDH) ([]byte, error) {
|
||||||
s := &btcec.PublicKey{}
|
hash, err := priv.ECDH(pub)
|
||||||
x, y := btcec.S256().ScalarMult(pub.X, pub.Y, priv.D.Bytes())
|
return hash[:], err
|
||||||
s.X = x
|
|
||||||
s.Y = y
|
|
||||||
|
|
||||||
h := sha256.Sum256(s.SerializeCompressed())
|
|
||||||
return h[:]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cipherState encapsulates the state for the AEAD which will be used to
|
// cipherState encapsulates the state for the AEAD which will be used to
|
||||||
@ -289,8 +285,8 @@ type handshakeState struct {
|
|||||||
|
|
||||||
initiator bool
|
initiator bool
|
||||||
|
|
||||||
localStatic *btcec.PrivateKey
|
localStatic keychain.SingleKeyECDH
|
||||||
localEphemeral *btcec.PrivateKey
|
localEphemeral keychain.SingleKeyECDH // nolint (false positive)
|
||||||
|
|
||||||
remoteStatic *btcec.PublicKey
|
remoteStatic *btcec.PublicKey
|
||||||
remoteEphemeral *btcec.PublicKey
|
remoteEphemeral *btcec.PublicKey
|
||||||
@ -300,11 +296,12 @@ type handshakeState struct {
|
|||||||
// with the prologue and protocol name. If this is the responder's handshake
|
// with the prologue and protocol name. If this is the responder's handshake
|
||||||
// state, then the remotePub can be nil.
|
// state, then the remotePub can be nil.
|
||||||
func newHandshakeState(initiator bool, prologue []byte,
|
func newHandshakeState(initiator bool, prologue []byte,
|
||||||
localPub *btcec.PrivateKey, remotePub *btcec.PublicKey) handshakeState {
|
localKey keychain.SingleKeyECDH,
|
||||||
|
remotePub *btcec.PublicKey) handshakeState {
|
||||||
|
|
||||||
h := handshakeState{
|
h := handshakeState{
|
||||||
initiator: initiator,
|
initiator: initiator,
|
||||||
localStatic: localPub,
|
localStatic: localKey,
|
||||||
remoteStatic: remotePub,
|
remoteStatic: remotePub,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,7 +319,7 @@ func newHandshakeState(initiator bool, prologue []byte,
|
|||||||
if initiator {
|
if initiator {
|
||||||
h.mixHash(remotePub.SerializeCompressed())
|
h.mixHash(remotePub.SerializeCompressed())
|
||||||
} else {
|
} else {
|
||||||
h.mixHash(localPub.PubKey().SerializeCompressed())
|
h.mixHash(localKey.PubKey().SerializeCompressed())
|
||||||
}
|
}
|
||||||
|
|
||||||
return h
|
return h
|
||||||
@ -393,11 +390,11 @@ type Machine struct {
|
|||||||
// string "lightning" as the prologue. The last parameter is a set of variadic
|
// string "lightning" as the prologue. The last parameter is a set of variadic
|
||||||
// arguments for adding additional options to the brontide Machine
|
// arguments for adding additional options to the brontide Machine
|
||||||
// initialization.
|
// initialization.
|
||||||
func NewBrontideMachine(initiator bool, localPub *btcec.PrivateKey,
|
func NewBrontideMachine(initiator bool, localKey keychain.SingleKeyECDH,
|
||||||
remotePub *btcec.PublicKey, options ...func(*Machine)) *Machine {
|
remotePub *btcec.PublicKey, options ...func(*Machine)) *Machine {
|
||||||
|
|
||||||
handshake := newHandshakeState(
|
handshake := newHandshakeState(
|
||||||
initiator, lightningPrologue, localPub, remotePub,
|
initiator, lightningPrologue, localKey, remotePub,
|
||||||
)
|
)
|
||||||
|
|
||||||
m := &Machine{
|
m := &Machine{
|
||||||
@ -451,22 +448,25 @@ const (
|
|||||||
//
|
//
|
||||||
// -> e, es
|
// -> e, es
|
||||||
func (b *Machine) GenActOne() ([ActOneSize]byte, error) {
|
func (b *Machine) GenActOne() ([ActOneSize]byte, error) {
|
||||||
var (
|
var actOne [ActOneSize]byte
|
||||||
err error
|
|
||||||
actOne [ActOneSize]byte
|
|
||||||
)
|
|
||||||
|
|
||||||
// e
|
// e
|
||||||
b.localEphemeral, err = b.ephemeralGen()
|
localEphemeral, err := b.ephemeralGen()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return actOne, err
|
return actOne, err
|
||||||
}
|
}
|
||||||
|
b.localEphemeral = &keychain.PrivKeyECDH{
|
||||||
|
PrivKey: localEphemeral,
|
||||||
|
}
|
||||||
|
|
||||||
ephemeral := b.localEphemeral.PubKey().SerializeCompressed()
|
ephemeral := localEphemeral.PubKey().SerializeCompressed()
|
||||||
b.mixHash(ephemeral)
|
b.mixHash(ephemeral)
|
||||||
|
|
||||||
// es
|
// es
|
||||||
s := ecdh(b.remoteStatic, b.localEphemeral)
|
s, err := ecdh(b.remoteStatic, b.localEphemeral)
|
||||||
|
if err != nil {
|
||||||
|
return actOne, err
|
||||||
|
}
|
||||||
b.mixKey(s[:])
|
b.mixKey(s[:])
|
||||||
|
|
||||||
authPayload := b.EncryptAndHash([]byte{})
|
authPayload := b.EncryptAndHash([]byte{})
|
||||||
@ -508,7 +508,10 @@ func (b *Machine) RecvActOne(actOne [ActOneSize]byte) error {
|
|||||||
b.mixHash(b.remoteEphemeral.SerializeCompressed())
|
b.mixHash(b.remoteEphemeral.SerializeCompressed())
|
||||||
|
|
||||||
// es
|
// es
|
||||||
s := ecdh(b.remoteEphemeral, b.localStatic)
|
s, err := ecdh(b.remoteEphemeral, b.localStatic)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
b.mixKey(s)
|
b.mixKey(s)
|
||||||
|
|
||||||
// If the initiator doesn't know our static key, then this operation
|
// If the initiator doesn't know our static key, then this operation
|
||||||
@ -524,22 +527,25 @@ func (b *Machine) RecvActOne(actOne [ActOneSize]byte) error {
|
|||||||
//
|
//
|
||||||
// <- e, ee
|
// <- e, ee
|
||||||
func (b *Machine) GenActTwo() ([ActTwoSize]byte, error) {
|
func (b *Machine) GenActTwo() ([ActTwoSize]byte, error) {
|
||||||
var (
|
var actTwo [ActTwoSize]byte
|
||||||
err error
|
|
||||||
actTwo [ActTwoSize]byte
|
|
||||||
)
|
|
||||||
|
|
||||||
// e
|
// e
|
||||||
b.localEphemeral, err = b.ephemeralGen()
|
localEphemeral, err := b.ephemeralGen()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return actTwo, err
|
return actTwo, err
|
||||||
}
|
}
|
||||||
|
b.localEphemeral = &keychain.PrivKeyECDH{
|
||||||
|
PrivKey: localEphemeral,
|
||||||
|
}
|
||||||
|
|
||||||
ephemeral := b.localEphemeral.PubKey().SerializeCompressed()
|
ephemeral := localEphemeral.PubKey().SerializeCompressed()
|
||||||
b.mixHash(b.localEphemeral.PubKey().SerializeCompressed())
|
b.mixHash(localEphemeral.PubKey().SerializeCompressed())
|
||||||
|
|
||||||
// ee
|
// ee
|
||||||
s := ecdh(b.remoteEphemeral, b.localEphemeral)
|
s, err := ecdh(b.remoteEphemeral, b.localEphemeral)
|
||||||
|
if err != nil {
|
||||||
|
return actTwo, err
|
||||||
|
}
|
||||||
b.mixKey(s)
|
b.mixKey(s)
|
||||||
|
|
||||||
authPayload := b.EncryptAndHash([]byte{})
|
authPayload := b.EncryptAndHash([]byte{})
|
||||||
@ -580,7 +586,10 @@ func (b *Machine) RecvActTwo(actTwo [ActTwoSize]byte) error {
|
|||||||
b.mixHash(b.remoteEphemeral.SerializeCompressed())
|
b.mixHash(b.remoteEphemeral.SerializeCompressed())
|
||||||
|
|
||||||
// ee
|
// ee
|
||||||
s := ecdh(b.remoteEphemeral, b.localEphemeral)
|
s, err := ecdh(b.remoteEphemeral, b.localEphemeral)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
b.mixKey(s)
|
b.mixKey(s)
|
||||||
|
|
||||||
_, err = b.DecryptAndHash(p[:])
|
_, err = b.DecryptAndHash(p[:])
|
||||||
@ -600,7 +609,10 @@ func (b *Machine) GenActThree() ([ActThreeSize]byte, error) {
|
|||||||
ourPubkey := b.localStatic.PubKey().SerializeCompressed()
|
ourPubkey := b.localStatic.PubKey().SerializeCompressed()
|
||||||
ciphertext := b.EncryptAndHash(ourPubkey)
|
ciphertext := b.EncryptAndHash(ourPubkey)
|
||||||
|
|
||||||
s := ecdh(b.remoteEphemeral, b.localStatic)
|
s, err := ecdh(b.remoteEphemeral, b.localStatic)
|
||||||
|
if err != nil {
|
||||||
|
return actThree, err
|
||||||
|
}
|
||||||
b.mixKey(s)
|
b.mixKey(s)
|
||||||
|
|
||||||
authPayload := b.EncryptAndHash([]byte{})
|
authPayload := b.EncryptAndHash([]byte{})
|
||||||
@ -649,7 +661,10 @@ func (b *Machine) RecvActThree(actThree [ActThreeSize]byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// se
|
// se
|
||||||
se := ecdh(b.remoteStatic, b.localEphemeral)
|
se, err := ecdh(b.remoteStatic, b.localEphemeral)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
b.mixKey(se)
|
b.mixKey(se)
|
||||||
|
|
||||||
if _, err := b.DecryptAndHash(p[:]); err != nil {
|
if _, err := b.DecryptAndHash(p[:]); err != nil {
|
||||||
@ -875,11 +890,11 @@ func (b *Machine) ReadBody(r io.Reader, buf []byte) ([]byte, error) {
|
|||||||
// This allows us to log the Machine object without spammy log messages.
|
// This allows us to log the Machine object without spammy log messages.
|
||||||
func (b *Machine) SetCurveToNil() {
|
func (b *Machine) SetCurveToNil() {
|
||||||
if b.localStatic != nil {
|
if b.localStatic != nil {
|
||||||
b.localStatic.Curve = nil
|
b.localStatic.PubKey().Curve = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.localEphemeral != nil {
|
if b.localEphemeral != nil {
|
||||||
b.localEphemeral.Curve = nil
|
b.localEphemeral.PubKey().Curve = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.remoteStatic != nil {
|
if b.remoteStatic != nil {
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"testing/iotest"
|
"testing/iotest"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -25,13 +26,14 @@ func makeListener() (*Listener, *lnwire.NetAddress, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
localKeyECDH := &keychain.PrivKeyECDH{PrivKey: localPriv}
|
||||||
|
|
||||||
// Having a port of ":0" means a random port, and interface will be
|
// Having a port of ":0" means a random port, and interface will be
|
||||||
// chosen for our listener.
|
// chosen for our listener.
|
||||||
addr := "localhost:0"
|
addr := "localhost:0"
|
||||||
|
|
||||||
// Our listener will be local, and the connection remote.
|
// Our listener will be local, and the connection remote.
|
||||||
listener, err := NewListener(localPriv, addr)
|
listener, err := NewListener(localKeyECDH, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -57,13 +59,14 @@ func establishTestConnection() (net.Conn, net.Conn, func(), error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
remoteKeyECDH := &keychain.PrivKeyECDH{PrivKey: remotePriv}
|
||||||
|
|
||||||
// Initiate a connection with a separate goroutine, and listen with our
|
// Initiate a connection with a separate goroutine, and listen with our
|
||||||
// main one. If both errors are nil, then encryption+auth was
|
// main one. If both errors are nil, then encryption+auth was
|
||||||
// successful.
|
// successful.
|
||||||
remoteConnChan := make(chan maybeNetConn, 1)
|
remoteConnChan := make(chan maybeNetConn, 1)
|
||||||
go func() {
|
go func() {
|
||||||
remoteConn, err := Dial(remotePriv, netAddr, net.Dial)
|
remoteConn, err := Dial(remoteKeyECDH, netAddr, net.Dial)
|
||||||
remoteConnChan <- maybeNetConn{remoteConn, err}
|
remoteConnChan <- maybeNetConn{remoteConn, err}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -190,9 +193,10 @@ func TestConcurrentHandshakes(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to generate private key: %v", err)
|
t.Fatalf("unable to generate private key: %v", err)
|
||||||
}
|
}
|
||||||
|
remoteKeyECDH := &keychain.PrivKeyECDH{PrivKey: remotePriv}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
remoteConn, err := Dial(remotePriv, netAddr, net.Dial)
|
remoteConn, err := Dial(remoteKeyECDH, netAddr, net.Dial)
|
||||||
connChan <- maybeNetConn{remoteConn, err}
|
connChan <- maybeNetConn{remoteConn, err}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -314,8 +318,10 @@ func TestBolt0008TestVectors(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to decode hex: %v", err)
|
t.Fatalf("unable to decode hex: %v", err)
|
||||||
}
|
}
|
||||||
initiatorPriv, _ := btcec.PrivKeyFromBytes(btcec.S256(),
|
initiatorPriv, _ := btcec.PrivKeyFromBytes(
|
||||||
initiatorKeyBytes)
|
btcec.S256(), initiatorKeyBytes,
|
||||||
|
)
|
||||||
|
initiatorKeyECDH := &keychain.PrivKeyECDH{PrivKey: initiatorPriv}
|
||||||
|
|
||||||
// We'll then do the same for the responder.
|
// We'll then do the same for the responder.
|
||||||
responderKeyBytes, err := hex.DecodeString("212121212121212121212121" +
|
responderKeyBytes, err := hex.DecodeString("212121212121212121212121" +
|
||||||
@ -323,8 +329,10 @@ func TestBolt0008TestVectors(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to decode hex: %v", err)
|
t.Fatalf("unable to decode hex: %v", err)
|
||||||
}
|
}
|
||||||
responderPriv, responderPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
responderPriv, responderPub := btcec.PrivKeyFromBytes(
|
||||||
responderKeyBytes)
|
btcec.S256(), responderKeyBytes,
|
||||||
|
)
|
||||||
|
responderKeyECDH := &keychain.PrivKeyECDH{PrivKey: responderPriv}
|
||||||
|
|
||||||
// With the initiator's key data parsed, we'll now define a custom
|
// With the initiator's key data parsed, we'll now define a custom
|
||||||
// EphemeralGenerator function for the state machine to ensure that the
|
// EphemeralGenerator function for the state machine to ensure that the
|
||||||
@ -355,10 +363,12 @@ func TestBolt0008TestVectors(t *testing.T) {
|
|||||||
|
|
||||||
// Finally, we'll create both brontide state machines, so we can begin
|
// Finally, we'll create both brontide state machines, so we can begin
|
||||||
// our test.
|
// our test.
|
||||||
initiator := NewBrontideMachine(true, initiatorPriv, responderPub,
|
initiator := NewBrontideMachine(
|
||||||
initiatorEphemeral)
|
true, initiatorKeyECDH, responderPub, initiatorEphemeral,
|
||||||
responder := NewBrontideMachine(false, responderPriv, nil,
|
)
|
||||||
responderEphemeral)
|
responder := NewBrontideMachine(
|
||||||
|
false, responderKeyECDH, nil, responderEphemeral,
|
||||||
|
)
|
||||||
|
|
||||||
// We'll start with the initiator generating the initial payload for
|
// We'll start with the initiator generating the initial payload for
|
||||||
// act one. This should consist of exactly 50 bytes. We'll assert that
|
// act one. This should consist of exactly 50 bytes. We'll assert that
|
||||||
|
2
go.mod
2
go.mod
@ -37,7 +37,7 @@ require (
|
|||||||
github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec
|
github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec
|
||||||
github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200
|
github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200
|
||||||
github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d
|
github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d
|
||||||
github.com/lightningnetwork/lightning-onion v1.0.1
|
github.com/lightningnetwork/lightning-onion v1.0.2-0.20200501022730-3c8c8d0b89ea
|
||||||
github.com/lightningnetwork/lnd/cert v1.0.2
|
github.com/lightningnetwork/lnd/cert v1.0.2
|
||||||
github.com/lightningnetwork/lnd/queue v1.0.4
|
github.com/lightningnetwork/lnd/queue v1.0.4
|
||||||
github.com/lightningnetwork/lnd/ticker v1.0.0
|
github.com/lightningnetwork/lnd/ticker v1.0.0
|
||||||
|
4
go.sum
4
go.sum
@ -159,8 +159,8 @@ github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200 h1:j4iZ1
|
|||||||
github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200/go.mod h1:MlZmoKa7CJP3eR1s5yB7Rm5aSyadpKkxqAwLQmog7N0=
|
github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200/go.mod h1:MlZmoKa7CJP3eR1s5yB7Rm5aSyadpKkxqAwLQmog7N0=
|
||||||
github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d h1:QWD/5MPnaZfUVP7P8wLa4M8Td2DI7XXHXt2vhVtUgGI=
|
github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d h1:QWD/5MPnaZfUVP7P8wLa4M8Td2DI7XXHXt2vhVtUgGI=
|
||||||
github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d/go.mod h1:KDb67YMzoh4eudnzClmvs2FbiLG9vxISmLApUkCa4uI=
|
github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d/go.mod h1:KDb67YMzoh4eudnzClmvs2FbiLG9vxISmLApUkCa4uI=
|
||||||
github.com/lightningnetwork/lightning-onion v1.0.1 h1:qChGgS5+aPxFeR6JiUsGvanei1bn6WJpYbvosw/1604=
|
github.com/lightningnetwork/lightning-onion v1.0.2-0.20200501022730-3c8c8d0b89ea h1:oCj48NQ8u7Vz+MmzHqt0db6mxcFZo3Ho7M5gCJauY/k=
|
||||||
github.com/lightningnetwork/lightning-onion v1.0.1/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4=
|
github.com/lightningnetwork/lightning-onion v1.0.2-0.20200501022730-3c8c8d0b89ea/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4=
|
||||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw=
|
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw=
|
||||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY=
|
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY=
|
||||||
github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA=
|
github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA=
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||||
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -84,7 +85,8 @@ func initTestExtracter() {
|
|||||||
// db and no garbage collection.
|
// db and no garbage collection.
|
||||||
func newOnionProcessor(t *testing.T) *hop.OnionProcessor {
|
func newOnionProcessor(t *testing.T) *hop.OnionProcessor {
|
||||||
sphinxRouter := sphinx.NewRouter(
|
sphinxRouter := sphinx.NewRouter(
|
||||||
sphinxPrivKey, &bitcoinCfg.SimNetParams, sphinx.NewMemoryReplayLog(),
|
&keychain.PrivKeyECDH{PrivKey: sphinxPrivKey},
|
||||||
|
&bitcoinCfg.SimNetParams, sphinx.NewMemoryReplayLog(),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := sphinxRouter.Start(); err != nil {
|
if err := sphinxRouter.Start(); err != nil {
|
||||||
|
@ -247,7 +247,9 @@ func (b *BtcWalletKeyRing) DeriveKey(keyLoc KeyLocator) (KeyDescriptor, error) {
|
|||||||
// passed key descriptor.
|
// passed key descriptor.
|
||||||
//
|
//
|
||||||
// NOTE: This is part of the keychain.SecretKeyRing interface.
|
// NOTE: This is part of the keychain.SecretKeyRing interface.
|
||||||
func (b *BtcWalletKeyRing) DerivePrivKey(keyDesc KeyDescriptor) (*btcec.PrivateKey, error) {
|
func (b *BtcWalletKeyRing) DerivePrivKey(keyDesc KeyDescriptor) (
|
||||||
|
*btcec.PrivateKey, error) {
|
||||||
|
|
||||||
var key *btcec.PrivateKey
|
var key *btcec.PrivateKey
|
||||||
|
|
||||||
db := b.wallet.Database()
|
db := b.wallet.Database()
|
||||||
@ -345,21 +347,21 @@ func (b *BtcWalletKeyRing) DerivePrivKey(keyDesc KeyDescriptor) (*btcec.PrivateK
|
|||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScalarMult performs a scalar multiplication (ECDH-like operation) between
|
// ECDH performs a scalar multiplication (ECDH-like operation) between the
|
||||||
// the target key descriptor and remote public key. The output returned will be
|
// target key descriptor and remote public key. The output returned will be
|
||||||
// the sha256 of the resulting shared point serialized in compressed format. If
|
// 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
|
// k is our private key, and P is the public key, we perform the following
|
||||||
// operation:
|
// operation:
|
||||||
//
|
//
|
||||||
// sx := k*P s := sha256(sx.SerializeCompressed())
|
// sx := k*P s := sha256(sx.SerializeCompressed())
|
||||||
//
|
//
|
||||||
// NOTE: This is part of the keychain.SecretKeyRing interface.
|
// NOTE: This is part of the keychain.ECDHRing interface.
|
||||||
func (b *BtcWalletKeyRing) ScalarMult(keyDesc KeyDescriptor,
|
func (b *BtcWalletKeyRing) ECDH(keyDesc KeyDescriptor,
|
||||||
pub *btcec.PublicKey) ([]byte, error) {
|
pub *btcec.PublicKey) ([32]byte, error) {
|
||||||
|
|
||||||
privKey, err := b.DerivePrivKey(keyDesc)
|
privKey, err := b.DerivePrivKey(keyDesc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return [32]byte{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s := &btcec.PublicKey{}
|
s := &btcec.PublicKey{}
|
||||||
@ -369,5 +371,34 @@ func (b *BtcWalletKeyRing) ScalarMult(keyDesc KeyDescriptor,
|
|||||||
|
|
||||||
h := sha256.Sum256(s.SerializeCompressed())
|
h := sha256.Sum256(s.SerializeCompressed())
|
||||||
|
|
||||||
return h[:], nil
|
return h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignDigest signs the given SHA256 message digest with the private key
|
||||||
|
// described in the key descriptor.
|
||||||
|
//
|
||||||
|
// NOTE: This is part of the keychain.DigestSignerRing interface.
|
||||||
|
func (b *BtcWalletKeyRing) SignDigest(keyDesc KeyDescriptor,
|
||||||
|
digest [32]byte) (*btcec.Signature, error) {
|
||||||
|
|
||||||
|
privKey, err := b.DerivePrivKey(keyDesc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return privKey.Sign(digest[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// NOTE: This is part of the keychain.DigestSignerRing interface.
|
||||||
|
func (b *BtcWalletKeyRing) SignDigestCompact(keyDesc KeyDescriptor,
|
||||||
|
digest [32]byte) ([]byte, error) {
|
||||||
|
|
||||||
|
privKey, err := b.DerivePrivKey(keyDesc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return btcec.SignCompact(btcec.S256(), privKey, digest[:], true)
|
||||||
}
|
}
|
||||||
|
@ -167,8 +167,8 @@ type KeyRing interface {
|
|||||||
DeriveKey(keyLoc KeyLocator) (KeyDescriptor, error)
|
DeriveKey(keyLoc KeyLocator) (KeyDescriptor, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecretKeyRing is a similar to the regular KeyRing interface, but it is also
|
// SecretKeyRing is a ring similar to the regular KeyRing interface, but it is
|
||||||
// able to derive *private keys*. As this is a super-set of the regular
|
// 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
|
// 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
|
// 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
|
// order to accept inbound network connections, or to do manual signing for
|
||||||
@ -176,22 +176,74 @@ type KeyRing interface {
|
|||||||
type SecretKeyRing interface {
|
type SecretKeyRing interface {
|
||||||
KeyRing
|
KeyRing
|
||||||
|
|
||||||
|
ECDHRing
|
||||||
|
|
||||||
|
DigestSignerRing
|
||||||
|
|
||||||
// DerivePrivKey attempts to derive the private key that corresponds to
|
// DerivePrivKey attempts to derive the private key that corresponds to
|
||||||
// the passed key descriptor. If the public key is set, then this
|
// 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
|
// 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
|
// MaxKeyRangeScan keys. In order for this to work, the caller MUST set
|
||||||
// the KeyFamily within the partially populated KeyLocator.
|
// the KeyFamily within the partially populated KeyLocator.
|
||||||
DerivePrivKey(keyDesc KeyDescriptor) (*btcec.PrivateKey, error)
|
DerivePrivKey(keyDesc KeyDescriptor) (*btcec.PrivateKey, error)
|
||||||
|
}
|
||||||
|
|
||||||
// ScalarMult performs a scalar multiplication (ECDH-like operation)
|
// DigestSignerRing is an interface that abstracts away basic low-level ECDSA
|
||||||
// between the target key descriptor and remote public key. The output
|
// 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
|
// 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
|
// in compressed format. If k is our private key, and P is the public
|
||||||
// key, we perform the following operation:
|
// key, we perform the following operation:
|
||||||
//
|
//
|
||||||
// sx := k*P
|
// sx := k*P
|
||||||
// s := sha256(sx.SerializeCompressed())
|
// s := sha256(sx.SerializeCompressed())
|
||||||
ScalarMult(keyDesc KeyDescriptor, pubKey *btcec.PublicKey) ([]byte, error)
|
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?
|
// TODO(roasbeef): extend to actually support scalar mult of key?
|
||||||
|
82
keychain/ecdh.go
Normal file
82
keychain/ecdh.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package keychain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/btcec"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewPubKeyECDH wraps the given key of the key ring so it adheres to the
|
||||||
|
// SingleKeyECDH interface.
|
||||||
|
func NewPubKeyECDH(keyDesc KeyDescriptor, ecdh ECDHRing) *PubKeyECDH {
|
||||||
|
return &PubKeyECDH{
|
||||||
|
keyDesc: keyDesc,
|
||||||
|
ecdh: ecdh,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PubKeyECDH is an implementation of the SingleKeyECDH interface. It wraps an
|
||||||
|
// ECDH key ring so it can perform ECDH shared key generation against a single
|
||||||
|
// abstracted away private key.
|
||||||
|
type PubKeyECDH struct {
|
||||||
|
keyDesc KeyDescriptor
|
||||||
|
ecdh ECDHRing
|
||||||
|
}
|
||||||
|
|
||||||
|
// PubKey returns the public key of the private key that is abstracted away by
|
||||||
|
// the interface.
|
||||||
|
//
|
||||||
|
// NOTE: This is part of the SingleKeyECDH interface.
|
||||||
|
func (p *PubKeyECDH) PubKey() *btcec.PublicKey {
|
||||||
|
return p.keyDesc.PubKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// ECDH performs a scalar multiplication (ECDH-like operation) between the
|
||||||
|
// abstracted private key and a 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())
|
||||||
|
//
|
||||||
|
// NOTE: This is part of the SingleKeyECDH interface.
|
||||||
|
func (p *PubKeyECDH) ECDH(pubKey *btcec.PublicKey) ([32]byte, error) {
|
||||||
|
return p.ecdh.ECDH(p.keyDesc, pubKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrivKeyECDH is an implementation of the SingleKeyECDH in which we do have the
|
||||||
|
// full private key. This can be used to wrap a temporary key to conform to the
|
||||||
|
// SingleKeyECDH interface.
|
||||||
|
type PrivKeyECDH struct {
|
||||||
|
// PrivKey is the private key that is used for the ECDH operation.
|
||||||
|
PrivKey *btcec.PrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// PubKey returns the public key of the private key that is abstracted away by
|
||||||
|
// the interface.
|
||||||
|
//
|
||||||
|
// NOTE: This is part of the SingleKeyECDH interface.
|
||||||
|
func (p *PrivKeyECDH) PubKey() *btcec.PublicKey {
|
||||||
|
return p.PrivKey.PubKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ECDH performs a scalar multiplication (ECDH-like operation) between the
|
||||||
|
// abstracted private key and a 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())
|
||||||
|
//
|
||||||
|
// NOTE: This is part of the SingleKeyECDH interface.
|
||||||
|
func (p *PrivKeyECDH) ECDH(pub *btcec.PublicKey) ([32]byte, error) {
|
||||||
|
s := &btcec.PublicKey{}
|
||||||
|
s.X, s.Y = btcec.S256().ScalarMult(pub.X, pub.Y, p.PrivKey.D.Bytes())
|
||||||
|
|
||||||
|
return sha256.Sum256(s.SerializeCompressed()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ SingleKeyECDH = (*PubKeyECDH)(nil)
|
||||||
|
var _ SingleKeyECDH = (*PrivKeyECDH)(nil)
|
56
keychain/signer.go
Normal file
56
keychain/signer.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package keychain
|
||||||
|
|
||||||
|
import "github.com/btcsuite/btcd/btcec"
|
||||||
|
|
||||||
|
func NewPubKeyDigestSigner(keyDesc KeyDescriptor,
|
||||||
|
signer DigestSignerRing) *PubKeyDigestSigner {
|
||||||
|
|
||||||
|
return &PubKeyDigestSigner{
|
||||||
|
keyDesc: keyDesc,
|
||||||
|
digestSigner: signer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PubKeyDigestSigner struct {
|
||||||
|
keyDesc KeyDescriptor
|
||||||
|
digestSigner DigestSignerRing
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PubKeyDigestSigner) PubKey() *btcec.PublicKey {
|
||||||
|
return p.keyDesc.PubKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PubKeyDigestSigner) SignDigest(digest [32]byte) (*btcec.Signature,
|
||||||
|
error) {
|
||||||
|
|
||||||
|
return p.digestSigner.SignDigest(p.keyDesc, digest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PubKeyDigestSigner) SignDigestCompact(digest [32]byte) ([]byte,
|
||||||
|
error) {
|
||||||
|
|
||||||
|
return p.digestSigner.SignDigestCompact(p.keyDesc, digest)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrivKeyDigestSigner struct {
|
||||||
|
PrivKey *btcec.PrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivKeyDigestSigner) PubKey() *btcec.PublicKey {
|
||||||
|
return p.PrivKey.PubKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivKeyDigestSigner) SignDigest(digest [32]byte) (*btcec.Signature,
|
||||||
|
error) {
|
||||||
|
|
||||||
|
return p.PrivKey.Sign(digest[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivKeyDigestSigner) SignDigestCompact(digest [32]byte) ([]byte,
|
||||||
|
error) {
|
||||||
|
|
||||||
|
return btcec.SignCompact(btcec.S256(), p.PrivKey, digest[:], true)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ SingleKeyDigestSigner = (*PubKeyDigestSigner)(nil)
|
||||||
|
var _ SingleKeyDigestSigner = (*PrivKeyDigestSigner)(nil)
|
33
lnd.go
33
lnd.go
@ -27,7 +27,6 @@ import (
|
|||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/btcsuite/btcwallet/wallet"
|
"github.com/btcsuite/btcwallet/wallet"
|
||||||
proxy "github.com/grpc-ecosystem/grpc-gateway/runtime"
|
proxy "github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||||
@ -471,18 +470,17 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error {
|
|||||||
cfg.registeredChains.RegisterChain(primaryChain, activeChainControl)
|
cfg.registeredChains.RegisterChain(primaryChain, activeChainControl)
|
||||||
|
|
||||||
// TODO(roasbeef): add rotation
|
// TODO(roasbeef): add rotation
|
||||||
idPrivKey, err := activeChainControl.wallet.DerivePrivKey(keychain.KeyDescriptor{
|
idKeyDesc, err := activeChainControl.keyRing.DeriveKey(
|
||||||
KeyLocator: keychain.KeyLocator{
|
keychain.KeyLocator{
|
||||||
Family: keychain.KeyFamilyNodeKey,
|
Family: keychain.KeyFamilyNodeKey,
|
||||||
Index: 0,
|
Index: 0,
|
||||||
},
|
},
|
||||||
})
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("unable to derive node private key: %v", err)
|
err := fmt.Errorf("error deriving node key: %v", err)
|
||||||
ltndLog.Error(err)
|
ltndLog.Error(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
idPrivKey.Curve = btcec.S256()
|
|
||||||
|
|
||||||
if cfg.Tor.Active {
|
if cfg.Tor.Active {
|
||||||
srvrLog.Infof("Proxying all network traffic via Tor "+
|
srvrLog.Infof("Proxying all network traffic via Tor "+
|
||||||
@ -545,17 +543,14 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error {
|
|||||||
}
|
}
|
||||||
defer towerDB.Close()
|
defer towerDB.Close()
|
||||||
|
|
||||||
towerPrivKey, err := activeChainControl.wallet.DerivePrivKey(
|
towerKeyDesc, err := activeChainControl.keyRing.DeriveKey(
|
||||||
keychain.KeyDescriptor{
|
keychain.KeyLocator{
|
||||||
KeyLocator: keychain.KeyLocator{
|
Family: keychain.KeyFamilyTowerID,
|
||||||
Family: keychain.KeyFamilyTowerID,
|
Index: 0,
|
||||||
Index: 0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("unable to derive watchtower "+
|
err := fmt.Errorf("error deriving tower key: %v", err)
|
||||||
"private key: %v", err)
|
|
||||||
ltndLog.Error(err)
|
ltndLog.Error(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -570,9 +565,11 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error {
|
|||||||
lnwallet.WitnessPubKey, false,
|
lnwallet.WitnessPubKey, false,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
NodePrivKey: towerPrivKey,
|
NodeKeyECDH: keychain.NewPubKeyECDH(
|
||||||
PublishTx: activeChainControl.wallet.PublishTransaction,
|
towerKeyDesc, activeChainControl.keyRing,
|
||||||
ChainHash: *activeNetParams.GenesisHash,
|
),
|
||||||
|
PublishTx: activeChainControl.wallet.PublishTransaction,
|
||||||
|
ChainHash: *activeNetParams.GenesisHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is a tor controller (user wants auto hidden services), then
|
// If there is a tor controller (user wants auto hidden services), then
|
||||||
@ -612,7 +609,7 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error {
|
|||||||
// connections.
|
// connections.
|
||||||
server, err := newServer(
|
server, err := newServer(
|
||||||
cfg, cfg.Listeners, chanDB, towerClientDB, activeChainControl,
|
cfg, cfg.Listeners, chanDB, towerClientDB, activeChainControl,
|
||||||
idPrivKey, walletInitParams.ChansToRestore, chainedAcceptor,
|
&idKeyDesc, walletInitParams.ChansToRestore, chainedAcceptor,
|
||||||
torController,
|
torController,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -5,7 +5,6 @@ package signrpc
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -415,24 +414,21 @@ func (s *Server) SignMessage(ctx context.Context,
|
|||||||
return nil, fmt.Errorf("a key locator MUST be passed in")
|
return nil, fmt.Errorf("a key locator MUST be passed in")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive the private key we'll be using for signing.
|
// Describe the private key we'll be using for signing.
|
||||||
keyLocator := keychain.KeyLocator{
|
keyDescriptor := keychain.KeyDescriptor{
|
||||||
Family: keychain.KeyFamily(in.KeyLoc.KeyFamily),
|
KeyLocator: keychain.KeyLocator{
|
||||||
Index: uint32(in.KeyLoc.KeyIndex),
|
Family: keychain.KeyFamily(in.KeyLoc.KeyFamily),
|
||||||
}
|
Index: uint32(in.KeyLoc.KeyIndex),
|
||||||
privKey, err := s.cfg.KeyRing.DerivePrivKey(keychain.KeyDescriptor{
|
},
|
||||||
KeyLocator: keyLocator,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("can't derive private key: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The signature is over the sha256 hash of the message.
|
// The signature is over the sha256 hash of the message.
|
||||||
digest := chainhash.HashB(in.Msg)
|
var digest [32]byte
|
||||||
|
copy(digest[:], chainhash.HashB(in.Msg))
|
||||||
|
|
||||||
// Create the raw ECDSA signature first and convert it to the final wire
|
// Create the raw ECDSA signature first and convert it to the final wire
|
||||||
// format after.
|
// format after.
|
||||||
sig, err := privKey.Sign(digest)
|
sig, err := s.cfg.KeyRing.SignDigest(keyDescriptor, digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't sign the hash: %v", err)
|
return nil, fmt.Errorf("can't sign the hash: %v", err)
|
||||||
}
|
}
|
||||||
@ -515,31 +511,15 @@ func (s *Server) DeriveSharedKey(_ context.Context, in *SharedKeyRequest) (
|
|||||||
locator.Index = uint32(in.KeyLoc.KeyIndex)
|
locator.Index = uint32(in.KeyLoc.KeyIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive our node's private key from the key ring.
|
// Derive the shared key using ECDH and hashing the serialized
|
||||||
idPrivKey, err := s.cfg.KeyRing.DerivePrivKey(keychain.KeyDescriptor{
|
// compressed shared point.
|
||||||
KeyLocator: locator,
|
keyDescriptor := keychain.KeyDescriptor{KeyLocator: locator}
|
||||||
})
|
sharedKeyHash, err := s.cfg.KeyRing.ECDH(keyDescriptor, ephemeralPubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("unable to derive node private key: %v", err)
|
err := fmt.Errorf("unable to derive shared key: %v", err)
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
idPrivKey.Curve = btcec.S256()
|
|
||||||
|
|
||||||
// Derive the shared key using ECDH and hashing the serialized
|
return &SharedKeyResponse{SharedKey: sharedKeyHash[:]}, nil
|
||||||
// compressed shared point.
|
|
||||||
sharedKeyHash := ecdh(ephemeralPubkey, idPrivKey)
|
|
||||||
return &SharedKeyResponse{SharedKey: sharedKeyHash}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ecdh performs an ECDH operation between pub and priv. The returned value is
|
|
||||||
// the sha256 of the compressed shared point.
|
|
||||||
func ecdh(pub *btcec.PublicKey, priv *btcec.PrivateKey) []byte {
|
|
||||||
s := &btcec.PublicKey{}
|
|
||||||
x, y := btcec.S256().ScalarMult(pub.X, pub.Y, priv.D.Bytes())
|
|
||||||
s.X = x
|
|
||||||
s.Y = y
|
|
||||||
|
|
||||||
h := sha256.Sum256(s.SerializeCompressed())
|
|
||||||
return h[:]
|
|
||||||
}
|
}
|
||||||
|
21
mock.go
21
mock.go
@ -359,7 +359,22 @@ func (m *mockSecretKeyRing) DerivePrivKey(keyDesc keychain.KeyDescriptor) (*btce
|
|||||||
return m.rootKey, nil
|
return m.rootKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockSecretKeyRing) ScalarMult(keyDesc keychain.KeyDescriptor,
|
func (m *mockSecretKeyRing) ECDH(_ keychain.KeyDescriptor,
|
||||||
pubKey *btcec.PublicKey) ([]byte, error) {
|
pubKey *btcec.PublicKey) ([32]byte, error) {
|
||||||
return nil, nil
|
|
||||||
|
return [32]byte{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockSecretKeyRing) SignDigest(_ keychain.KeyDescriptor,
|
||||||
|
digest [32]byte) (*btcec.Signature, error) {
|
||||||
|
|
||||||
|
return m.rootKey.Sign(digest[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockSecretKeyRing) SignDigestCompact(_ keychain.KeyDescriptor,
|
||||||
|
digest [32]byte) ([]byte, error) {
|
||||||
|
|
||||||
|
return btcec.SignCompact(btcec.S256(), m.rootKey, digest[:], true)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ keychain.SecretKeyRing = (*mockSecretKeyRing)(nil)
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/netann"
|
"github.com/lightningnetwork/lnd/netann"
|
||||||
)
|
)
|
||||||
@ -309,6 +310,7 @@ func newManagerCfg(t *testing.T, numChannels int,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to generate key pair: %v", err)
|
t.Fatalf("unable to generate key pair: %v", err)
|
||||||
}
|
}
|
||||||
|
privKeySigner := &keychain.PrivKeyDigestSigner{PrivKey: privKey}
|
||||||
|
|
||||||
graph := newMockGraph(
|
graph := newMockGraph(
|
||||||
t, numChannels, startEnabled, startEnabled, privKey.PubKey(),
|
t, numChannels, startEnabled, startEnabled, privKey.PubKey(),
|
||||||
@ -320,7 +322,7 @@ func newManagerCfg(t *testing.T, numChannels int,
|
|||||||
ChanEnableTimeout: 500 * time.Millisecond,
|
ChanEnableTimeout: 500 * time.Millisecond,
|
||||||
ChanDisableTimeout: time.Second,
|
ChanDisableTimeout: time.Second,
|
||||||
OurPubKey: privKey.PubKey(),
|
OurPubKey: privKey.PubKey(),
|
||||||
MessageSigner: netann.NewNodeSigner(privKey),
|
MessageSigner: netann.NewNodeSigner(privKeySigner),
|
||||||
IsChannelActive: htlcSwitch.HasActiveLink,
|
IsChannelActive: htlcSwitch.HasActiveLink,
|
||||||
ApplyChannelUpdate: graph.ApplyChannelUpdate,
|
ApplyChannelUpdate: graph.ApplyChannelUpdate,
|
||||||
DB: graph,
|
DB: graph,
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/netann"
|
"github.com/lightningnetwork/lnd/netann"
|
||||||
@ -30,7 +31,8 @@ func (m *mockSigner) SignMessage(pk *btcec.PublicKey,
|
|||||||
var _ lnwallet.MessageSigner = (*mockSigner)(nil)
|
var _ lnwallet.MessageSigner = (*mockSigner)(nil)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
privKey, _ = btcec.NewPrivateKey(btcec.S256())
|
privKey, _ = btcec.NewPrivateKey(btcec.S256())
|
||||||
|
privKeySigner = &keychain.PrivKeyDigestSigner{PrivKey: privKey}
|
||||||
|
|
||||||
pubKey = privKey.PubKey()
|
pubKey = privKey.PubKey()
|
||||||
|
|
||||||
@ -52,35 +54,35 @@ var updateDisableTests = []updateDisableTest{
|
|||||||
startEnabled: true,
|
startEnabled: true,
|
||||||
disable: true,
|
disable: true,
|
||||||
startTime: time.Now(),
|
startTime: time.Now(),
|
||||||
signer: netann.NewNodeSigner(privKey),
|
signer: netann.NewNodeSigner(privKeySigner),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "working signer enabled to enabled",
|
name: "working signer enabled to enabled",
|
||||||
startEnabled: true,
|
startEnabled: true,
|
||||||
disable: false,
|
disable: false,
|
||||||
startTime: time.Now(),
|
startTime: time.Now(),
|
||||||
signer: netann.NewNodeSigner(privKey),
|
signer: netann.NewNodeSigner(privKeySigner),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "working signer disabled to enabled",
|
name: "working signer disabled to enabled",
|
||||||
startEnabled: false,
|
startEnabled: false,
|
||||||
disable: false,
|
disable: false,
|
||||||
startTime: time.Now(),
|
startTime: time.Now(),
|
||||||
signer: netann.NewNodeSigner(privKey),
|
signer: netann.NewNodeSigner(privKeySigner),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "working signer disabled to disabled",
|
name: "working signer disabled to disabled",
|
||||||
startEnabled: false,
|
startEnabled: false,
|
||||||
disable: true,
|
disable: true,
|
||||||
startTime: time.Now(),
|
startTime: time.Now(),
|
||||||
signer: netann.NewNodeSigner(privKey),
|
signer: netann.NewNodeSigner(privKeySigner),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "working signer future monotonicity",
|
name: "working signer future monotonicity",
|
||||||
startEnabled: true,
|
startEnabled: true,
|
||||||
disable: true,
|
disable: true,
|
||||||
startTime: time.Now().Add(time.Hour), // must increment
|
startTime: time.Now().Add(time.Hour), // must increment
|
||||||
signer: netann.NewNodeSigner(privKey),
|
signer: netann.NewNodeSigner(privKeySigner),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "failing signer",
|
name: "failing signer",
|
||||||
|
@ -6,25 +6,21 @@ import (
|
|||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeSigner is an implementation of the MessageSigner interface backed by the
|
// NodeSigner is an implementation of the MessageSigner interface backed by the
|
||||||
// identity private key of running lnd node.
|
// identity private key of running lnd node.
|
||||||
type NodeSigner struct {
|
type NodeSigner struct {
|
||||||
privKey *btcec.PrivateKey
|
keySigner keychain.SingleKeyDigestSigner
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNodeSigner creates a new instance of the NodeSigner backed by the target
|
// NewNodeSigner creates a new instance of the NodeSigner backed by the target
|
||||||
// private key.
|
// private key.
|
||||||
func NewNodeSigner(key *btcec.PrivateKey) *NodeSigner {
|
func NewNodeSigner(keySigner keychain.SingleKeyDigestSigner) *NodeSigner {
|
||||||
priv := &btcec.PrivateKey{}
|
|
||||||
priv.Curve = btcec.S256()
|
|
||||||
priv.PublicKey.X = key.X
|
|
||||||
priv.PublicKey.Y = key.Y
|
|
||||||
priv.D = key.D
|
|
||||||
return &NodeSigner{
|
return &NodeSigner{
|
||||||
privKey: priv,
|
keySigner: keySigner,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,13 +32,14 @@ func (n *NodeSigner) SignMessage(pubKey *btcec.PublicKey,
|
|||||||
|
|
||||||
// If this isn't our identity public key, then we'll exit early with an
|
// If this isn't our identity public key, then we'll exit early with an
|
||||||
// error as we can't sign with this key.
|
// error as we can't sign with this key.
|
||||||
if !pubKey.IsEqual(n.privKey.PubKey()) {
|
if !pubKey.IsEqual(n.keySigner.PubKey()) {
|
||||||
return nil, fmt.Errorf("unknown public key")
|
return nil, fmt.Errorf("unknown public key")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we'll sign the dsha256 of the target message.
|
// Otherwise, we'll sign the dsha256 of the target message.
|
||||||
digest := chainhash.DoubleHashB(msg)
|
var digest [32]byte
|
||||||
sig, err := n.privKey.Sign(digest)
|
copy(digest[:], chainhash.DoubleHashB(msg))
|
||||||
|
sig, err := n.keySigner.SignDigest(digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't sign the message: %v", err)
|
return nil, fmt.Errorf("can't sign the message: %v", err)
|
||||||
}
|
}
|
||||||
@ -63,14 +60,11 @@ func (n *NodeSigner) SignCompact(msg []byte) ([]byte, error) {
|
|||||||
// SignDigestCompact signs the provided message digest under the resident
|
// SignDigestCompact signs the provided message digest under the resident
|
||||||
// node's private key. The returned signature is a pubkey-recoverable signature.
|
// node's private key. The returned signature is a pubkey-recoverable signature.
|
||||||
func (n *NodeSigner) SignDigestCompact(hash []byte) ([]byte, error) {
|
func (n *NodeSigner) SignDigestCompact(hash []byte) ([]byte, error) {
|
||||||
|
var digest [32]byte
|
||||||
|
copy(digest[:], hash)
|
||||||
|
|
||||||
// Should the signature reference a compressed public key or not.
|
// keychain.SignDigestCompact returns a pubkey-recoverable signature.
|
||||||
isCompressedKey := true
|
sig, err := n.keySigner.SignDigestCompact(digest)
|
||||||
|
|
||||||
// btcec.SignCompact returns a pubkey-recoverable signature
|
|
||||||
sig, err := btcec.SignCompact(
|
|
||||||
btcec.S256(), n.privKey, hash, isCompressedKey,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't sign the hash: %v", err)
|
return nil, fmt.Errorf("can't sign the hash: %v", err)
|
||||||
}
|
}
|
||||||
|
2
peer.go
2
peer.go
@ -555,7 +555,7 @@ func (p *peer) loadActiveChannels(chans []*channeldb.OpenChannel) (
|
|||||||
// particular channel.
|
// particular channel.
|
||||||
var selfPolicy *channeldb.ChannelEdgePolicy
|
var selfPolicy *channeldb.ChannelEdgePolicy
|
||||||
if info != nil && bytes.Equal(info.NodeKey1Bytes[:],
|
if info != nil && bytes.Equal(info.NodeKey1Bytes[:],
|
||||||
p.server.identityPriv.PubKey().SerializeCompressed()) {
|
p.server.identityECDH.PubKey().SerializeCompressed()) {
|
||||||
|
|
||||||
selfPolicy = p1
|
selfPolicy = p1
|
||||||
} else {
|
} else {
|
||||||
|
2
pilot.go
2
pilot.go
@ -170,7 +170,7 @@ func initAutoPilot(svr *server, cfg *lncfg.AutoPilot,
|
|||||||
|
|
||||||
// With the heuristic itself created, we can now populate the remainder
|
// With the heuristic itself created, we can now populate the remainder
|
||||||
// of the items that the autopilot agent needs to perform its duties.
|
// of the items that the autopilot agent needs to perform its duties.
|
||||||
self := svr.identityPriv.PubKey()
|
self := svr.identityECDH.PubKey()
|
||||||
pilotCfg := autopilot.Config{
|
pilotCfg := autopilot.Config{
|
||||||
Self: self,
|
Self: self,
|
||||||
Heuristic: weightedAttachment,
|
Heuristic: weightedAttachment,
|
||||||
|
@ -1433,7 +1433,7 @@ func (r *rpcServer) ConnectPeer(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Connections to ourselves are disallowed for obvious reasons.
|
// Connections to ourselves are disallowed for obvious reasons.
|
||||||
if pubKey.IsEqual(r.server.identityPriv.PubKey()) {
|
if pubKey.IsEqual(r.server.identityECDH.PubKey()) {
|
||||||
return nil, fmt.Errorf("cannot make connection to self")
|
return nil, fmt.Errorf("cannot make connection to self")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1781,7 +1781,7 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
|
|||||||
|
|
||||||
// Making a channel to ourselves wouldn't be of any use, so we
|
// Making a channel to ourselves wouldn't be of any use, so we
|
||||||
// explicitly disallow them.
|
// explicitly disallow them.
|
||||||
if nodePubKey.IsEqual(r.server.identityPriv.PubKey()) {
|
if nodePubKey.IsEqual(r.server.identityECDH.PubKey()) {
|
||||||
return nil, fmt.Errorf("cannot open channel to self")
|
return nil, fmt.Errorf("cannot open channel to self")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2406,7 +2406,7 @@ func (r *rpcServer) GetInfo(ctx context.Context,
|
|||||||
}
|
}
|
||||||
nPendingChannels := uint32(len(pendingChannels))
|
nPendingChannels := uint32(len(pendingChannels))
|
||||||
|
|
||||||
idPub := r.server.identityPriv.PubKey().SerializeCompressed()
|
idPub := r.server.identityECDH.PubKey().SerializeCompressed()
|
||||||
encodedIDPub := hex.EncodeToString(idPub)
|
encodedIDPub := hex.EncodeToString(idPub)
|
||||||
|
|
||||||
bestHash, bestHeight, err := r.server.cc.chainIO.GetBestBlock()
|
bestHash, bestHeight, err := r.server.cc.chainIO.GetBestBlock()
|
||||||
@ -4637,7 +4637,7 @@ func (r *rpcServer) GetTransactions(ctx context.Context,
|
|||||||
// To remain backwards compatible with the old api, default to the
|
// To remain backwards compatible with the old api, default to the
|
||||||
// special case end height which will return transactions from the start
|
// special case end height which will return transactions from the start
|
||||||
// height until the chain tip, including unconfirmed transactions.
|
// height until the chain tip, including unconfirmed transactions.
|
||||||
var endHeight int32 = btcwallet.UnconfirmedHeight
|
var endHeight = btcwallet.UnconfirmedHeight
|
||||||
|
|
||||||
// If the user has provided an end height, we overwrite our default.
|
// If the user has provided an end height, we overwrite our default.
|
||||||
if req.EndHeight != 0 {
|
if req.EndHeight != 0 {
|
||||||
|
65
server.go
65
server.go
@ -41,6 +41,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/invoices"
|
"github.com/lightningnetwork/lnd/invoices"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lncfg"
|
"github.com/lightningnetwork/lnd/lncfg"
|
||||||
"github.com/lightningnetwork/lnd/lnpeer"
|
"github.com/lightningnetwork/lnd/lnpeer"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
@ -135,9 +136,9 @@ type server struct {
|
|||||||
|
|
||||||
cfg *Config
|
cfg *Config
|
||||||
|
|
||||||
// identityPriv is the private key used to authenticate any incoming
|
// identityECDH is an ECDH capable wrapper for the private key used
|
||||||
// connections.
|
// to authenticate any incoming connections.
|
||||||
identityPriv *btcec.PrivateKey
|
identityECDH keychain.SingleKeyECDH
|
||||||
|
|
||||||
// nodeSigner is an implementation of the MessageSigner implementation
|
// nodeSigner is an implementation of the MessageSigner implementation
|
||||||
// that's backed by the identity private key of the running lnd node.
|
// that's backed by the identity private key of the running lnd node.
|
||||||
@ -311,12 +312,12 @@ func parseAddr(address string, netCfg tor.Net) (net.Addr, error) {
|
|||||||
|
|
||||||
// noiseDial is a factory function which creates a connmgr compliant dialing
|
// noiseDial is a factory function which creates a connmgr compliant dialing
|
||||||
// function by returning a closure which includes the server's identity key.
|
// function by returning a closure which includes the server's identity key.
|
||||||
func noiseDial(idPriv *btcec.PrivateKey,
|
func noiseDial(idKey keychain.SingleKeyECDH,
|
||||||
netCfg tor.Net) func(net.Addr) (net.Conn, error) {
|
netCfg tor.Net) func(net.Addr) (net.Conn, error) {
|
||||||
|
|
||||||
return func(a net.Addr) (net.Conn, error) {
|
return func(a net.Addr) (net.Conn, error) {
|
||||||
lnAddr := a.(*lnwire.NetAddress)
|
lnAddr := a.(*lnwire.NetAddress)
|
||||||
return brontide.Dial(idPriv, lnAddr, netCfg.Dial)
|
return brontide.Dial(idKey, lnAddr, netCfg.Dial)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,12 +325,18 @@ func noiseDial(idPriv *btcec.PrivateKey,
|
|||||||
// passed listener address.
|
// passed listener address.
|
||||||
func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
||||||
towerClientDB *wtdb.ClientDB, cc *chainControl,
|
towerClientDB *wtdb.ClientDB, cc *chainControl,
|
||||||
privKey *btcec.PrivateKey,
|
nodeKeyDesc *keychain.KeyDescriptor,
|
||||||
chansToRestore walletunlocker.ChannelsToRecover,
|
chansToRestore walletunlocker.ChannelsToRecover,
|
||||||
chanPredicate chanacceptor.ChannelAcceptor,
|
chanPredicate chanacceptor.ChannelAcceptor,
|
||||||
torController *tor.Controller) (*server, error) {
|
torController *tor.Controller) (*server, error) {
|
||||||
|
|
||||||
var err error
|
var (
|
||||||
|
err error
|
||||||
|
nodeKeyECDH = keychain.NewPubKeyECDH(*nodeKeyDesc, cc.keyRing)
|
||||||
|
nodeKeySigner = keychain.NewPubKeyDigestSigner(
|
||||||
|
*nodeKeyDesc, cc.keyRing,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
listeners := make([]net.Listener, len(listenAddrs))
|
listeners := make([]net.Listener, len(listenAddrs))
|
||||||
for i, listenAddr := range listenAddrs {
|
for i, listenAddr := range listenAddrs {
|
||||||
@ -337,7 +344,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
// doesn't need to call the general lndResolveTCP function
|
// doesn't need to call the general lndResolveTCP function
|
||||||
// since we are resolving a local address.
|
// since we are resolving a local address.
|
||||||
listeners[i], err = brontide.NewListener(
|
listeners[i], err = brontide.NewListener(
|
||||||
privKey, listenAddr.String(),
|
nodeKeyECDH, listenAddr.String(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -366,14 +373,16 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
}
|
}
|
||||||
|
|
||||||
var serializedPubKey [33]byte
|
var serializedPubKey [33]byte
|
||||||
copy(serializedPubKey[:], privKey.PubKey().SerializeCompressed())
|
copy(serializedPubKey[:], nodeKeyECDH.PubKey().SerializeCompressed())
|
||||||
|
|
||||||
// Initialize the sphinx router, placing it's persistent replay log in
|
// Initialize the sphinx router, placing it's persistent replay log in
|
||||||
// the same directory as the channel graph database.
|
// the same directory as the channel graph database.
|
||||||
graphDir := chanDB.Path()
|
graphDir := chanDB.Path()
|
||||||
sharedSecretPath := filepath.Join(graphDir, "sphinxreplay.db")
|
sharedSecretPath := filepath.Join(graphDir, "sphinxreplay.db")
|
||||||
replayLog := htlcswitch.NewDecayedLog(sharedSecretPath, cc.chainNotifier)
|
replayLog := htlcswitch.NewDecayedLog(sharedSecretPath, cc.chainNotifier)
|
||||||
sphinxRouter := sphinx.NewRouter(privKey, activeNetParams.Params, replayLog)
|
sphinxRouter := sphinx.NewRouter(
|
||||||
|
nodeKeyECDH, activeNetParams.Params, replayLog,
|
||||||
|
)
|
||||||
|
|
||||||
writeBufferPool := pool.NewWriteBuffer(
|
writeBufferPool := pool.NewWriteBuffer(
|
||||||
pool.DefaultWriteBufferGCInterval,
|
pool.DefaultWriteBufferGCInterval,
|
||||||
@ -425,8 +434,8 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
|
|
||||||
channelNotifier: channelnotifier.New(chanDB),
|
channelNotifier: channelnotifier.New(chanDB),
|
||||||
|
|
||||||
identityPriv: privKey,
|
identityECDH: nodeKeyECDH,
|
||||||
nodeSigner: netann.NewNodeSigner(privKey),
|
nodeSigner: netann.NewNodeSigner(nodeKeySigner),
|
||||||
|
|
||||||
listenAddrs: listenAddrs,
|
listenAddrs: listenAddrs,
|
||||||
|
|
||||||
@ -512,7 +521,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
ChanStatusSampleInterval: cfg.ChanStatusSampleInterval,
|
ChanStatusSampleInterval: cfg.ChanStatusSampleInterval,
|
||||||
ChanEnableTimeout: cfg.ChanEnableTimeout,
|
ChanEnableTimeout: cfg.ChanEnableTimeout,
|
||||||
ChanDisableTimeout: cfg.ChanDisableTimeout,
|
ChanDisableTimeout: cfg.ChanDisableTimeout,
|
||||||
OurPubKey: privKey.PubKey(),
|
OurPubKey: nodeKeyECDH.PubKey(),
|
||||||
MessageSigner: s.nodeSigner,
|
MessageSigner: s.nodeSigner,
|
||||||
IsChannelActive: s.htlcSwitch.HasActiveLink,
|
IsChannelActive: s.htlcSwitch.HasActiveLink,
|
||||||
ApplyChannelUpdate: s.applyChannelUpdate,
|
ApplyChannelUpdate: s.applyChannelUpdate,
|
||||||
@ -638,7 +647,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
Features: s.featureMgr.Get(feature.SetNodeAnn),
|
Features: s.featureMgr.Get(feature.SetNodeAnn),
|
||||||
Color: color,
|
Color: color,
|
||||||
}
|
}
|
||||||
copy(selfNode.PubKeyBytes[:], privKey.PubKey().SerializeCompressed())
|
copy(selfNode.PubKeyBytes[:], nodeKeyECDH.PubKey().SerializeCompressed())
|
||||||
|
|
||||||
// Based on the disk representation of the node announcement generated
|
// Based on the disk representation of the node announcement generated
|
||||||
// above, we'll generate a node announcement that can go out on the
|
// above, we'll generate a node announcement that can go out on the
|
||||||
@ -651,7 +660,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
// With the announcement generated, we'll sign it to properly
|
// With the announcement generated, we'll sign it to properly
|
||||||
// authenticate the message on the network.
|
// authenticate the message on the network.
|
||||||
authSig, err := netann.SignAnnouncement(
|
authSig, err := netann.SignAnnouncement(
|
||||||
s.nodeSigner, s.identityPriv.PubKey(), nodeAnn,
|
s.nodeSigner, s.identityECDH.PubKey(), nodeAnn,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to generate signature for "+
|
return nil, fmt.Errorf("unable to generate signature for "+
|
||||||
@ -799,7 +808,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
SubBatchDelay: time.Second * 5,
|
SubBatchDelay: time.Second * 5,
|
||||||
IgnoreHistoricalFilters: cfg.IgnoreHistoricalGossipFilters,
|
IgnoreHistoricalFilters: cfg.IgnoreHistoricalGossipFilters,
|
||||||
},
|
},
|
||||||
s.identityPriv.PubKey(),
|
s.identityECDH.PubKey(),
|
||||||
)
|
)
|
||||||
|
|
||||||
s.localChanMgr = &localchans.Manager{
|
s.localChanMgr = &localchans.Manager{
|
||||||
@ -980,7 +989,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.fundingMgr, err = newFundingManager(fundingConfig{
|
s.fundingMgr, err = newFundingManager(fundingConfig{
|
||||||
IDKey: privKey.PubKey(),
|
IDKey: nodeKeyECDH.PubKey(),
|
||||||
Wallet: cc.wallet,
|
Wallet: cc.wallet,
|
||||||
PublishTransaction: cc.wallet.PublishTransaction,
|
PublishTransaction: cc.wallet.PublishTransaction,
|
||||||
Notifier: cc.chainNotifier,
|
Notifier: cc.chainNotifier,
|
||||||
@ -988,7 +997,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
SignMessage: func(pubKey *btcec.PublicKey,
|
SignMessage: func(pubKey *btcec.PublicKey,
|
||||||
msg []byte) (input.Signature, error) {
|
msg []byte) (input.Signature, error) {
|
||||||
|
|
||||||
if pubKey.IsEqual(privKey.PubKey()) {
|
if pubKey.IsEqual(nodeKeyECDH.PubKey()) {
|
||||||
return s.nodeSigner.SignMessage(pubKey, msg)
|
return s.nodeSigner.SignMessage(pubKey, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1001,7 +1010,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
optionalFields ...discovery.OptionalMsgField) chan error {
|
optionalFields ...discovery.OptionalMsgField) chan error {
|
||||||
|
|
||||||
return s.authGossiper.ProcessLocalAnnouncement(
|
return s.authGossiper.ProcessLocalAnnouncement(
|
||||||
msg, privKey.PubKey(), optionalFields...,
|
msg, nodeKeyECDH.PubKey(), optionalFields...,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
NotifyWhenOnline: s.NotifyWhenOnline,
|
NotifyWhenOnline: s.NotifyWhenOnline,
|
||||||
@ -1227,7 +1236,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
OnAccept: s.InboundPeerConnected,
|
OnAccept: s.InboundPeerConnected,
|
||||||
RetryDuration: time.Second * 5,
|
RetryDuration: time.Second * 5,
|
||||||
TargetOutbound: 100,
|
TargetOutbound: 100,
|
||||||
Dial: noiseDial(s.identityPriv, s.cfg.net),
|
Dial: noiseDial(s.identityECDH, s.cfg.net),
|
||||||
OnConnection: s.OutboundPeerConnected,
|
OnConnection: s.OutboundPeerConnected,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2020,7 +2029,7 @@ func (s *server) createNewHiddenService() error {
|
|||||||
Color: newNodeAnn.RGBColor,
|
Color: newNodeAnn.RGBColor,
|
||||||
AuthSigBytes: newNodeAnn.Signature.ToSignatureBytes(),
|
AuthSigBytes: newNodeAnn.Signature.ToSignatureBytes(),
|
||||||
}
|
}
|
||||||
copy(selfNode.PubKeyBytes[:], s.identityPriv.PubKey().SerializeCompressed())
|
copy(selfNode.PubKeyBytes[:], s.identityECDH.PubKey().SerializeCompressed())
|
||||||
if err := s.chanDB.ChannelGraph().SetSourceNode(selfNode); err != nil {
|
if err := s.chanDB.ChannelGraph().SetSourceNode(selfNode); err != nil {
|
||||||
return fmt.Errorf("can't set self node: %v", err)
|
return fmt.Errorf("can't set self node: %v", err)
|
||||||
}
|
}
|
||||||
@ -2050,7 +2059,7 @@ func (s *server) genNodeAnnouncement(refresh bool,
|
|||||||
// Otherwise, we'll sign a new update after applying all of the passed
|
// Otherwise, we'll sign a new update after applying all of the passed
|
||||||
// modifiers.
|
// modifiers.
|
||||||
err := netann.SignNodeAnnouncement(
|
err := netann.SignNodeAnnouncement(
|
||||||
s.nodeSigner, s.identityPriv.PubKey(), s.currentNodeAnn,
|
s.nodeSigner, s.identityECDH.PubKey(), s.currentNodeAnn,
|
||||||
modifiers...,
|
modifiers...,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2102,7 +2111,7 @@ func (s *server) establishPersistentConnections() error {
|
|||||||
|
|
||||||
// TODO(roasbeef): instead iterate over link nodes and query graph for
|
// TODO(roasbeef): instead iterate over link nodes and query graph for
|
||||||
// each of the nodes.
|
// each of the nodes.
|
||||||
selfPub := s.identityPriv.PubKey().SerializeCompressed()
|
selfPub := s.identityECDH.PubKey().SerializeCompressed()
|
||||||
err = sourceNode.ForEachChannel(nil, func(
|
err = sourceNode.ForEachChannel(nil, func(
|
||||||
tx kvdb.ReadTx,
|
tx kvdb.ReadTx,
|
||||||
chanInfo *channeldb.ChannelEdgeInfo,
|
chanInfo *channeldb.ChannelEdgeInfo,
|
||||||
@ -2552,7 +2561,7 @@ func (s *server) InboundPeerConnected(conn net.Conn) {
|
|||||||
// not of the same type of the new connection (inbound), then
|
// not of the same type of the new connection (inbound), then
|
||||||
// we'll close out the new connection s.t there's only a single
|
// we'll close out the new connection s.t there's only a single
|
||||||
// connection between us.
|
// connection between us.
|
||||||
localPub := s.identityPriv.PubKey()
|
localPub := s.identityECDH.PubKey()
|
||||||
if !connectedPeer.inbound &&
|
if !connectedPeer.inbound &&
|
||||||
!shouldDropLocalConnection(localPub, nodePub) {
|
!shouldDropLocalConnection(localPub, nodePub) {
|
||||||
|
|
||||||
@ -2663,7 +2672,7 @@ func (s *server) OutboundPeerConnected(connReq *connmgr.ConnReq, conn net.Conn)
|
|||||||
// not of the same type of the new connection (outbound), then
|
// not of the same type of the new connection (outbound), then
|
||||||
// we'll close out the new connection s.t there's only a single
|
// we'll close out the new connection s.t there's only a single
|
||||||
// connection between us.
|
// connection between us.
|
||||||
localPub := s.identityPriv.PubKey()
|
localPub := s.identityECDH.PubKey()
|
||||||
if connectedPeer.inbound &&
|
if connectedPeer.inbound &&
|
||||||
shouldDropLocalConnection(localPub, nodePub) {
|
shouldDropLocalConnection(localPub, nodePub) {
|
||||||
|
|
||||||
@ -3264,7 +3273,7 @@ func (s *server) ConnectToPeer(addr *lnwire.NetAddress, perm bool) error {
|
|||||||
// notify the caller if the connection attempt has failed. Otherwise, it will be
|
// notify the caller if the connection attempt has failed. Otherwise, it will be
|
||||||
// closed.
|
// closed.
|
||||||
func (s *server) connectToPeer(addr *lnwire.NetAddress, errChan chan<- error) {
|
func (s *server) connectToPeer(addr *lnwire.NetAddress, errChan chan<- error) {
|
||||||
conn, err := brontide.Dial(s.identityPriv, addr, s.cfg.net.Dial)
|
conn, err := brontide.Dial(s.identityECDH, addr, s.cfg.net.Dial)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
srvrLog.Errorf("Unable to connect to %v: %v", addr, err)
|
srvrLog.Errorf("Unable to connect to %v: %v", addr, err)
|
||||||
select {
|
select {
|
||||||
@ -3467,7 +3476,7 @@ func (s *server) fetchNodeAdvertisedAddr(pub *btcec.PublicKey) (net.Addr, error)
|
|||||||
func (s *server) fetchLastChanUpdate() func(lnwire.ShortChannelID) (
|
func (s *server) fetchLastChanUpdate() func(lnwire.ShortChannelID) (
|
||||||
*lnwire.ChannelUpdate, error) {
|
*lnwire.ChannelUpdate, error) {
|
||||||
|
|
||||||
ourPubKey := s.identityPriv.PubKey().SerializeCompressed()
|
ourPubKey := s.identityECDH.PubKey().SerializeCompressed()
|
||||||
return func(cid lnwire.ShortChannelID) (*lnwire.ChannelUpdate, error) {
|
return func(cid lnwire.ShortChannelID) (*lnwire.ChannelUpdate, error) {
|
||||||
info, edge1, edge2, err := s.chanRouter.GetChannelByID(cid)
|
info, edge1, edge2, err := s.chanRouter.GetChannelByID(cid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -3483,7 +3492,7 @@ func (s *server) fetchLastChanUpdate() func(lnwire.ShortChannelID) (
|
|||||||
// applyChannelUpdate applies the channel update to the different sub-systems of
|
// applyChannelUpdate applies the channel update to the different sub-systems of
|
||||||
// the server.
|
// the server.
|
||||||
func (s *server) applyChannelUpdate(update *lnwire.ChannelUpdate) error {
|
func (s *server) applyChannelUpdate(update *lnwire.ChannelUpdate) error {
|
||||||
pubKey := s.identityPriv.PubKey()
|
pubKey := s.identityECDH.PubKey()
|
||||||
errChan := s.authGossiper.ProcessLocalAnnouncement(update, pubKey)
|
errChan := s.authGossiper.ProcessLocalAnnouncement(update, pubKey)
|
||||||
select {
|
select {
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
|
@ -103,10 +103,13 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, publTx chan *wire.MsgTx,
|
|||||||
updateChan func(a, b *channeldb.OpenChannel)) (*peer, *lnwallet.LightningChannel,
|
updateChan func(a, b *channeldb.OpenChannel)) (*peer, *lnwallet.LightningChannel,
|
||||||
*lnwallet.LightningChannel, func(), error) {
|
*lnwallet.LightningChannel, func(), error) {
|
||||||
|
|
||||||
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(
|
||||||
alicesPrivKey)
|
btcec.S256(), alicesPrivKey,
|
||||||
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
)
|
||||||
bobsPrivKey)
|
aliceKeySigner := &keychain.PrivKeyDigestSigner{PrivKey: aliceKeyPriv}
|
||||||
|
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(
|
||||||
|
btcec.S256(), bobsPrivKey,
|
||||||
|
)
|
||||||
|
|
||||||
channelCapacity := btcutil.Amount(10 * 1e8)
|
channelCapacity := btcutil.Amount(10 * 1e8)
|
||||||
channelBal := channelCapacity / 2
|
channelBal := channelCapacity / 2
|
||||||
@ -402,7 +405,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, publTx chan *wire.MsgTx,
|
|||||||
}
|
}
|
||||||
s.htlcSwitch = htlcSwitch
|
s.htlcSwitch = htlcSwitch
|
||||||
|
|
||||||
nodeSignerAlice := netann.NewNodeSigner(aliceKeyPriv)
|
nodeSignerAlice := netann.NewNodeSigner(aliceKeySigner)
|
||||||
|
|
||||||
const chanActiveTimeout = time.Minute
|
const chanActiveTimeout = time.Minute
|
||||||
|
|
||||||
|
@ -5,10 +5,10 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/tor"
|
"github.com/lightningnetwork/lnd/tor"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/lookout"
|
"github.com/lightningnetwork/lnd/watchtower/lookout"
|
||||||
)
|
)
|
||||||
@ -63,9 +63,9 @@ type Config struct {
|
|||||||
// successfully sent funds can be received.
|
// successfully sent funds can be received.
|
||||||
NewAddress func() (btcutil.Address, error)
|
NewAddress func() (btcutil.Address, error)
|
||||||
|
|
||||||
// NodePrivKey is private key to be used in accepting new brontide
|
// NodeKeyECDH is the ECDH capable wrapper of the key to be used in
|
||||||
// connections.
|
// accepting new brontide connections.
|
||||||
NodePrivKey *btcec.PrivateKey
|
NodeKeyECDH keychain.SingleKeyECDH
|
||||||
|
|
||||||
// PublishTx provides the ability to send a signed transaction to the
|
// PublishTx provides the ability to send a signed transaction to the
|
||||||
// network.
|
// network.
|
||||||
|
@ -72,7 +72,7 @@ func New(cfg *Config) (*Standalone, error) {
|
|||||||
listeners := make([]net.Listener, 0, len(cfg.ListenAddrs))
|
listeners := make([]net.Listener, 0, len(cfg.ListenAddrs))
|
||||||
for _, listenAddr := range cfg.ListenAddrs {
|
for _, listenAddr := range cfg.ListenAddrs {
|
||||||
listener, err := brontide.NewListener(
|
listener, err := brontide.NewListener(
|
||||||
cfg.NodePrivKey, listenAddr.String(),
|
cfg.NodeKeyECDH, listenAddr.String(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -85,7 +85,7 @@ func New(cfg *Config) (*Standalone, error) {
|
|||||||
server, err := wtserver.New(&wtserver.Config{
|
server, err := wtserver.New(&wtserver.Config{
|
||||||
ChainHash: cfg.ChainHash,
|
ChainHash: cfg.ChainHash,
|
||||||
DB: cfg.DB,
|
DB: cfg.DB,
|
||||||
NodePrivKey: cfg.NodePrivKey,
|
NodeKeyECDH: cfg.NodeKeyECDH,
|
||||||
Listeners: listeners,
|
Listeners: listeners,
|
||||||
ReadTimeout: cfg.ReadTimeout,
|
ReadTimeout: cfg.ReadTimeout,
|
||||||
WriteTimeout: cfg.WriteTimeout,
|
WriteTimeout: cfg.WriteTimeout,
|
||||||
@ -190,7 +190,7 @@ func (w *Standalone) createNewHiddenService() error {
|
|||||||
//
|
//
|
||||||
// NOTE: Part of the watchtowerrpc.WatchtowerBackend interface.
|
// NOTE: Part of the watchtowerrpc.WatchtowerBackend interface.
|
||||||
func (w *Standalone) PubKey() *btcec.PublicKey {
|
func (w *Standalone) PubKey() *btcec.PublicKey {
|
||||||
return w.cfg.NodePrivKey.PubKey()
|
return w.cfg.NodeKeyECDH.PubKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListeningAddrs returns the listening addresses where the watchtower server
|
// ListeningAddrs returns the listening addresses where the watchtower server
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
||||||
@ -132,7 +133,7 @@ type Config struct {
|
|||||||
// SecretKeyRing is used to derive the session keys used to communicate
|
// SecretKeyRing is used to derive the session keys used to communicate
|
||||||
// with the tower. The client only stores the KeyLocators internally so
|
// with the tower. The client only stores the KeyLocators internally so
|
||||||
// that we never store private keys on disk.
|
// that we never store private keys on disk.
|
||||||
SecretKeyRing SecretKeyRing
|
SecretKeyRing ECDHKeyRing
|
||||||
|
|
||||||
// Dial connects to an addr using the specified net and returns the
|
// Dial connects to an addr using the specified net and returns the
|
||||||
// connection object.
|
// connection object.
|
||||||
@ -337,7 +338,7 @@ func New(config *Config) (*TowerClient, error) {
|
|||||||
// NOTE: This method should only be used when deserialization of a
|
// NOTE: This method should only be used when deserialization of a
|
||||||
// ClientSession's Tower and SessionPrivKey fields is desired, otherwise, the
|
// ClientSession's Tower and SessionPrivKey fields is desired, otherwise, the
|
||||||
// existing ListClientSessions method should be used.
|
// existing ListClientSessions method should be used.
|
||||||
func getClientSessions(db DB, keyRing SecretKeyRing, forTower *wtdb.TowerID,
|
func getClientSessions(db DB, keyRing ECDHKeyRing, forTower *wtdb.TowerID,
|
||||||
passesFilter func(*wtdb.ClientSession) bool) (
|
passesFilter func(*wtdb.ClientSession) bool) (
|
||||||
map[wtdb.SessionID]*wtdb.ClientSession, error) {
|
map[wtdb.SessionID]*wtdb.ClientSession, error) {
|
||||||
|
|
||||||
@ -358,11 +359,14 @@ func getClientSessions(db DB, keyRing SecretKeyRing, forTower *wtdb.TowerID,
|
|||||||
}
|
}
|
||||||
s.Tower = tower
|
s.Tower = tower
|
||||||
|
|
||||||
sessionKey, err := DeriveSessionKey(keyRing, s.KeyIndex)
|
towerKeyDesc, err := keyRing.DeriveKey(keychain.KeyLocator{
|
||||||
|
Family: keychain.KeyFamilyTowerSession,
|
||||||
|
Index: s.KeyIndex,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s.SessionPrivKey = sessionKey
|
s.SessionKeyECDH = keychain.NewPubKeyECDH(towerKeyDesc, keyRing)
|
||||||
|
|
||||||
// If an optional filter was provided, use it to filter out any
|
// If an optional filter was provided, use it to filter out any
|
||||||
// undesired sessions.
|
// undesired sessions.
|
||||||
@ -897,10 +901,10 @@ func (c *TowerClient) taskRejected(task *backupTask, curStatus reserveStatus) {
|
|||||||
// dial connects the peer at addr using privKey as our secret key for the
|
// dial connects the peer at addr using privKey as our secret key for the
|
||||||
// connection. The connection will use the configured Net's resolver to resolve
|
// connection. The connection will use the configured Net's resolver to resolve
|
||||||
// the address for either Tor or clear net connections.
|
// the address for either Tor or clear net connections.
|
||||||
func (c *TowerClient) dial(privKey *btcec.PrivateKey,
|
func (c *TowerClient) dial(localKey keychain.SingleKeyECDH,
|
||||||
addr *lnwire.NetAddress) (wtserver.Peer, error) {
|
addr *lnwire.NetAddress) (wtserver.Peer, error) {
|
||||||
|
|
||||||
return c.cfg.AuthDial(privKey, addr, c.cfg.Dial)
|
return c.cfg.AuthDial(localKey, addr, c.cfg.Dial)
|
||||||
}
|
}
|
||||||
|
|
||||||
// readMessage receives and parses the next message from the given Peer. An
|
// readMessage receives and parses the next message from the given Peer. An
|
||||||
|
@ -101,10 +101,10 @@ func (m *mockNet) ResolveTCPAddr(network string, address string) (*net.TCPAddr,
|
|||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockNet) AuthDial(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress,
|
func (m *mockNet) AuthDial(local keychain.SingleKeyECDH, netAddr *lnwire.NetAddress,
|
||||||
dialer func(string, string) (net.Conn, error)) (wtserver.Peer, error) {
|
dialer func(string, string) (net.Conn, error)) (wtserver.Peer, error) {
|
||||||
|
|
||||||
localPk := localPriv.PubKey()
|
localPk := local.PubKey()
|
||||||
localAddr := &net.TCPAddr{
|
localAddr := &net.TCPAddr{
|
||||||
IP: net.IP{0x32, 0x31, 0x30, 0x29},
|
IP: net.IP{0x32, 0x31, 0x30, 0x29},
|
||||||
Port: 36723,
|
Port: 36723,
|
||||||
@ -401,6 +401,7 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to generate tower private key: %v", err)
|
t.Fatalf("Unable to generate tower private key: %v", err)
|
||||||
}
|
}
|
||||||
|
privKeyECDH := &keychain.PrivKeyECDH{PrivKey: privKey}
|
||||||
|
|
||||||
towerPubKey := privKey.PubKey()
|
towerPubKey := privKey.PubKey()
|
||||||
|
|
||||||
@ -416,7 +417,7 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness {
|
|||||||
DB: serverDB,
|
DB: serverDB,
|
||||||
ReadTimeout: timeout,
|
ReadTimeout: timeout,
|
||||||
WriteTimeout: timeout,
|
WriteTimeout: timeout,
|
||||||
NodePrivKey: privKey,
|
NodeKeyECDH: privKeyECDH,
|
||||||
NewAddress: func() (btcutil.Address, error) {
|
NewAddress: func() (btcutil.Address, error) {
|
||||||
return addr, nil
|
return addr, nil
|
||||||
},
|
},
|
||||||
@ -519,7 +520,7 @@ func (h *testHarness) startClient() {
|
|||||||
h.t.Fatalf("Unable to resolve tower TCP addr: %v", err)
|
h.t.Fatalf("Unable to resolve tower TCP addr: %v", err)
|
||||||
}
|
}
|
||||||
towerAddr := &lnwire.NetAddress{
|
towerAddr := &lnwire.NetAddress{
|
||||||
IdentityKey: h.serverCfg.NodePrivKey.PubKey(),
|
IdentityKey: h.serverCfg.NodeKeyECDH.PubKey(),
|
||||||
Address: towerTCPAddr,
|
Address: towerTCPAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
package wtclient
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DeriveSessionKey accepts an session key index for an existing session and
|
|
||||||
// derives the HD private key to be used to authenticate the brontide transport
|
|
||||||
// and authenticate requests sent to the tower. The key will use the
|
|
||||||
// keychain.KeyFamilyTowerSession and the provided index, giving a BIP43
|
|
||||||
// derivation path of:
|
|
||||||
//
|
|
||||||
// * m/1017'/coinType'/8/0/index
|
|
||||||
func DeriveSessionKey(keyRing SecretKeyRing,
|
|
||||||
index uint32) (*btcec.PrivateKey, error) {
|
|
||||||
|
|
||||||
return keyRing.DerivePrivKey(keychain.KeyDescriptor{
|
|
||||||
KeyLocator: keychain.KeyLocator{
|
|
||||||
Family: keychain.KeyFamilyTowerSession,
|
|
||||||
Index: index,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
@ -102,20 +102,24 @@ type Dial func(net, addr string) (net.Conn, error)
|
|||||||
// AuthDialer connects to a remote node using an authenticated transport, such as
|
// AuthDialer connects to a remote node using an authenticated transport, such as
|
||||||
// brontide. The dialer argument is used to specify a resolver, which allows
|
// brontide. The dialer argument is used to specify a resolver, which allows
|
||||||
// this method to be used over Tor or clear net connections.
|
// this method to be used over Tor or clear net connections.
|
||||||
type AuthDialer func(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress,
|
type AuthDialer func(localKey keychain.SingleKeyECDH, netAddr *lnwire.NetAddress,
|
||||||
dialer func(string, string) (net.Conn, error)) (wtserver.Peer, error)
|
dialer func(string, string) (net.Conn, error)) (wtserver.Peer, error)
|
||||||
|
|
||||||
// AuthDial is the watchtower client's default method of dialing.
|
// AuthDial is the watchtower client's default method of dialing.
|
||||||
func AuthDial(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress,
|
func AuthDial(localKey keychain.SingleKeyECDH, netAddr *lnwire.NetAddress,
|
||||||
dialer func(string, string) (net.Conn, error)) (wtserver.Peer, error) {
|
dialer func(string, string) (net.Conn, error)) (wtserver.Peer, error) {
|
||||||
|
|
||||||
return brontide.Dial(localPriv, netAddr, dialer)
|
return brontide.Dial(localKey, netAddr, dialer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecretKeyRing abstracts the ability to derive HD private keys given a
|
// ECDHKeyRing abstracts the ability to derive shared ECDH keys given a
|
||||||
// description of the derivation path.
|
// description of the derivation path of a private key.
|
||||||
type SecretKeyRing interface {
|
type ECDHKeyRing interface {
|
||||||
// DerivePrivKey derives the private key from the root seed using a
|
keychain.ECDHRing
|
||||||
// key descriptor specifying the key's derivation path.
|
|
||||||
DerivePrivKey(loc keychain.KeyDescriptor) (*btcec.PrivateKey, 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 keychain.KeyLocator) (keychain.KeyDescriptor, error)
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/blob"
|
"github.com/lightningnetwork/lnd/watchtower/blob"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
||||||
@ -44,7 +44,7 @@ type NegotiatorConfig struct {
|
|||||||
|
|
||||||
// SecretKeyRing allows the client to derive new session private keys
|
// SecretKeyRing allows the client to derive new session private keys
|
||||||
// when attempting to negotiate session with a tower.
|
// when attempting to negotiate session with a tower.
|
||||||
SecretKeyRing SecretKeyRing
|
SecretKeyRing ECDHKeyRing
|
||||||
|
|
||||||
// Candidates is an abstract set of tower candidates that the negotiator
|
// Candidates is an abstract set of tower candidates that the negotiator
|
||||||
// will traverse serially when attempting to negotiate a new session.
|
// will traverse serially when attempting to negotiate a new session.
|
||||||
@ -58,7 +58,8 @@ type NegotiatorConfig struct {
|
|||||||
// Dial initiates an outbound brontide connection to the given address
|
// Dial initiates an outbound brontide connection to the given address
|
||||||
// using a specified private key. The peer is returned in the event of a
|
// using a specified private key. The peer is returned in the event of a
|
||||||
// successful connection.
|
// successful connection.
|
||||||
Dial func(*btcec.PrivateKey, *lnwire.NetAddress) (wtserver.Peer, error)
|
Dial func(keychain.SingleKeyECDH, *lnwire.NetAddress) (wtserver.Peer,
|
||||||
|
error)
|
||||||
|
|
||||||
// SendMessage writes a wtwire message to remote peer.
|
// SendMessage writes a wtwire message to remote peer.
|
||||||
SendMessage func(wtserver.Peer, wtwire.Message) error
|
SendMessage func(wtserver.Peer, wtwire.Message) error
|
||||||
@ -315,13 +316,21 @@ func (n *sessionNegotiator) createSession(tower *wtdb.Tower,
|
|||||||
return ErrNoTowerAddrs
|
return ErrNoTowerAddrs
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionPriv, err := DeriveSessionKey(n.cfg.SecretKeyRing, keyIndex)
|
sessionKeyDesc, err := n.cfg.SecretKeyRing.DeriveKey(
|
||||||
|
keychain.KeyLocator{
|
||||||
|
Family: keychain.KeyFamilyTowerSession,
|
||||||
|
Index: keyIndex,
|
||||||
|
},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
sessionKey := keychain.NewPubKeyECDH(
|
||||||
|
sessionKeyDesc, n.cfg.SecretKeyRing,
|
||||||
|
)
|
||||||
|
|
||||||
for _, lnAddr := range tower.LNAddrs() {
|
for _, lnAddr := range tower.LNAddrs() {
|
||||||
err = n.tryAddress(sessionPriv, keyIndex, tower, lnAddr)
|
err := n.tryAddress(sessionKey, keyIndex, tower, lnAddr)
|
||||||
switch {
|
switch {
|
||||||
case err == ErrPermanentTowerFailure:
|
case err == ErrPermanentTowerFailure:
|
||||||
// TODO(conner): report to iterator? can then be reset
|
// TODO(conner): report to iterator? can then be reset
|
||||||
@ -346,11 +355,11 @@ func (n *sessionNegotiator) createSession(tower *wtdb.Tower,
|
|||||||
// The address should belong to the tower's set of addresses. This method only
|
// The address should belong to the tower's set of addresses. This method only
|
||||||
// returns true if all steps succeed and the new session has been persisted, and
|
// returns true if all steps succeed and the new session has been persisted, and
|
||||||
// fails otherwise.
|
// fails otherwise.
|
||||||
func (n *sessionNegotiator) tryAddress(privKey *btcec.PrivateKey,
|
func (n *sessionNegotiator) tryAddress(sessionKey keychain.SingleKeyECDH,
|
||||||
keyIndex uint32, tower *wtdb.Tower, lnAddr *lnwire.NetAddress) error {
|
keyIndex uint32, tower *wtdb.Tower, lnAddr *lnwire.NetAddress) error {
|
||||||
|
|
||||||
// Connect to the tower address using our generated session key.
|
// Connect to the tower address using our generated session key.
|
||||||
conn, err := n.cfg.Dial(privKey, lnAddr)
|
conn, err := n.cfg.Dial(sessionKey, lnAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -417,9 +426,7 @@ func (n *sessionNegotiator) tryAddress(privKey *btcec.PrivateKey,
|
|||||||
// TODO(conner): validate reward address
|
// TODO(conner): validate reward address
|
||||||
rewardPkScript := createSessionReply.Data
|
rewardPkScript := createSessionReply.Data
|
||||||
|
|
||||||
sessionID := wtdb.NewSessionIDFromPubKey(
|
sessionID := wtdb.NewSessionIDFromPubKey(sessionKey.PubKey())
|
||||||
privKey.PubKey(),
|
|
||||||
)
|
|
||||||
clientSession := &wtdb.ClientSession{
|
clientSession := &wtdb.ClientSession{
|
||||||
ClientSessionBody: wtdb.ClientSessionBody{
|
ClientSessionBody: wtdb.ClientSessionBody{
|
||||||
TowerID: tower.ID,
|
TowerID: tower.ID,
|
||||||
@ -428,7 +435,7 @@ func (n *sessionNegotiator) tryAddress(privKey *btcec.PrivateKey,
|
|||||||
RewardPkScript: rewardPkScript,
|
RewardPkScript: rewardPkScript,
|
||||||
},
|
},
|
||||||
Tower: tower,
|
Tower: tower,
|
||||||
SessionPrivKey: privKey,
|
SessionKeyECDH: sessionKey,
|
||||||
ID: sessionID,
|
ID: sessionID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/wtserver"
|
"github.com/lightningnetwork/lnd/watchtower/wtserver"
|
||||||
@ -41,8 +41,8 @@ type sessionQueueConfig struct {
|
|||||||
|
|
||||||
// Dial allows the client to dial the tower using it's public key and
|
// Dial allows the client to dial the tower using it's public key and
|
||||||
// net address.
|
// net address.
|
||||||
Dial func(*btcec.PrivateKey,
|
Dial func(keychain.SingleKeyECDH, *lnwire.NetAddress) (wtserver.Peer,
|
||||||
*lnwire.NetAddress) (wtserver.Peer, error)
|
error)
|
||||||
|
|
||||||
// SendMessage encodes, encrypts, and writes a message to the given peer.
|
// SendMessage encodes, encrypts, and writes a message to the given peer.
|
||||||
SendMessage func(wtserver.Peer, wtwire.Message) error
|
SendMessage func(wtserver.Peer, wtwire.Message) error
|
||||||
@ -285,7 +285,7 @@ func (q *sessionQueue) sessionManager() {
|
|||||||
// drainBackups attempts to send all pending updates in the queue to the tower.
|
// drainBackups attempts to send all pending updates in the queue to the tower.
|
||||||
func (q *sessionQueue) drainBackups() {
|
func (q *sessionQueue) drainBackups() {
|
||||||
// First, check that we are able to dial this session's tower.
|
// First, check that we are able to dial this session's tower.
|
||||||
conn, err := q.cfg.Dial(q.cfg.ClientSession.SessionPrivKey, q.towerAddr)
|
conn, err := q.cfg.Dial(q.cfg.ClientSession.SessionKeyECDH, q.towerAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("SessionQueue(%s) unable to dial tower at %v: %v",
|
log.Errorf("SessionQueue(%s) unable to dial tower at %v: %v",
|
||||||
q.ID(), q.towerAddr, err)
|
q.ID(), q.towerAddr, err)
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/blob"
|
"github.com/lightningnetwork/lnd/watchtower/blob"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/wtpolicy"
|
"github.com/lightningnetwork/lnd/watchtower/wtpolicy"
|
||||||
@ -60,12 +60,12 @@ type ClientSession struct {
|
|||||||
// tower with TowerID.
|
// tower with TowerID.
|
||||||
Tower *Tower
|
Tower *Tower
|
||||||
|
|
||||||
// SessionPrivKey is the ephemeral secret key used to connect to the
|
// SessionKeyECDH is the ECDH capable wrapper of the ephemeral secret
|
||||||
// watchtower.
|
// key used to connect to the watchtower.
|
||||||
//
|
//
|
||||||
// NOTE: This value is not serialized. It is derived using the KeyIndex
|
// NOTE: This value is not serialized. It is derived using the KeyIndex
|
||||||
// on startup to avoid storing private keys on disk.
|
// on startup to avoid storing private keys on disk.
|
||||||
SessionPrivKey *btcec.PrivateKey
|
SessionKeyECDH keychain.SingleKeyECDH
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientSessionBody represents the primary components of a ClientSession that
|
// ClientSessionBody represents the primary components of a ClientSession that
|
||||||
|
@ -20,25 +20,56 @@ func NewSecretKeyRing() *SecretKeyRing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DerivePrivKey derives the private key for a given key descriptor. If
|
// DeriveKey attempts to derive an arbitrary key specified by the
|
||||||
// this method is called twice with the same argument, it will return the same
|
// passed KeyLocator. This may be used in several recovery scenarios,
|
||||||
// private key.
|
// or when manually rotating something like our current default node
|
||||||
func (m *SecretKeyRing) DerivePrivKey(
|
// key.
|
||||||
desc keychain.KeyDescriptor) (*btcec.PrivateKey, error) {
|
//
|
||||||
|
// NOTE: This is part of the wtclient.ECDHKeyRing interface.
|
||||||
|
func (m *SecretKeyRing) DeriveKey(
|
||||||
|
keyLoc keychain.KeyLocator) (keychain.KeyDescriptor, error) {
|
||||||
|
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
if key, ok := m.keys[desc.KeyLocator]; ok {
|
if key, ok := m.keys[keyLoc]; ok {
|
||||||
return key, nil
|
return keychain.KeyDescriptor{
|
||||||
|
KeyLocator: keyLoc,
|
||||||
|
PubKey: key.PubKey(),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
privKey, err := btcec.NewPrivateKey(btcec.S256())
|
privKey, err := btcec.NewPrivateKey(btcec.S256())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return keychain.KeyDescriptor{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.keys[desc.KeyLocator] = privKey
|
m.keys[keyLoc] = privKey
|
||||||
|
|
||||||
return privKey, nil
|
return keychain.KeyDescriptor{
|
||||||
|
KeyLocator: keyLoc,
|
||||||
|
PubKey: privKey.PubKey(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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())
|
||||||
|
//
|
||||||
|
// NOTE: This is part of the wtclient.ECDHKeyRing interface.
|
||||||
|
func (m *SecretKeyRing) ECDH(keyDesc keychain.KeyDescriptor,
|
||||||
|
pub *btcec.PublicKey) ([32]byte, error) {
|
||||||
|
|
||||||
|
_, err := m.DeriveKey(keyDesc.KeyLocator)
|
||||||
|
if err != nil {
|
||||||
|
return [32]byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
privKey := m.keys[keyDesc.KeyLocator]
|
||||||
|
ecdh := &keychain.PrivKeyECDH{PrivKey: privKey}
|
||||||
|
return ecdh.ECDH(pub)
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,10 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/connmgr"
|
"github.com/btcsuite/btcd/connmgr"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/wtwire"
|
"github.com/lightningnetwork/lnd/watchtower/wtwire"
|
||||||
@ -33,9 +33,9 @@ type Config struct {
|
|||||||
// storing state updates.
|
// storing state updates.
|
||||||
DB DB
|
DB DB
|
||||||
|
|
||||||
// NodePrivKey is private key to be used in accepting new brontide
|
// NodeKeyECDH is the the ECDH capable wrapper of the key to be used in
|
||||||
// connections.
|
// accepting new brontide connections.
|
||||||
NodePrivKey *btcec.PrivateKey
|
NodeKeyECDH keychain.SingleKeyECDH
|
||||||
|
|
||||||
// Listeners specifies which address to which clients may connect.
|
// Listeners specifies which address to which clients may connect.
|
||||||
Listeners []net.Listener
|
Listeners []net.Listener
|
||||||
|
Loading…
Reference in New Issue
Block a user