Skip to content

Commit 6237246

Browse files
committed
multi: add DeriveSharedKey to key ring
We'll need to be able to derive a shared key using ECDH against a wallet key (while supporting remote signing) for the ECIES encryption in part 4 of the on-chain group key address support PR series. We can prepare for that by adding the already exising RPC method to the lnd key ring.
1 parent 787cb2a commit 6237246

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

key_ring.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package taprootassets
22

33
import (
44
"context"
5+
"crypto/sha256"
56
"fmt"
67

8+
"github.com/btcsuite/btcd/btcec/v2"
79
"github.com/lightninglabs/lndclient"
810
"github.com/lightninglabs/taproot-assets/asset"
911
"github.com/lightninglabs/taproot-assets/tapgarden"
@@ -88,6 +90,23 @@ func (l *LndRpcKeyRing) IsLocalKey(ctx context.Context,
8890
return derived.PubKey.IsEqual(desc.PubKey)
8991
}
9092

93+
// DeriveSharedKey returns a shared secret key by performing
94+
// Diffie-Hellman key derivation between the ephemeral public key and
95+
// the key specified by the key locator (or the node's identity private
96+
// key if no key locator is specified):
97+
//
98+
// P_shared = privKeyNode * ephemeralPubkey
99+
//
100+
// The resulting shared public key is serialized in the compressed
101+
// format and hashed with SHA256, resulting in a final key length of 256
102+
// bits.
103+
func (l *LndRpcKeyRing) DeriveSharedKey(ctx context.Context,
104+
ephemeralPubKey *btcec.PublicKey,
105+
keyLocator *keychain.KeyLocator) ([sha256.Size]byte, error) {
106+
107+
return l.lnd.Signer.DeriveSharedKey(ctx, ephemeralPubKey, keyLocator)
108+
}
109+
91110
// A compile time assertion to ensure LndRpcKeyRing meets the
92111
// tapgarden.KeyRing interface.
93112
var _ tapgarden.KeyRing = (*LndRpcKeyRing)(nil)

tapgarden/interface.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package tapgarden
22

33
import (
44
"context"
5+
"crypto/sha256"
56
"errors"
67
"fmt"
78

@@ -402,6 +403,19 @@ type KeyRing interface {
402403
// IsLocalKey returns true if the key is under the control of the wallet
403404
// and can be derived by it.
404405
IsLocalKey(context.Context, keychain.KeyDescriptor) bool
406+
407+
// DeriveSharedKey returns a shared secret key by performing
408+
// Diffie-Hellman key derivation between the ephemeral public key and
409+
// the key specified by the key locator (or the node's identity private
410+
// key if no key locator is specified):
411+
//
412+
// P_shared = privKeyNode * ephemeralPubkey
413+
//
414+
// The resulting shared public key is serialized in the compressed
415+
// format and hashed with SHA256, resulting in a final key length of 256
416+
// bits.
417+
DeriveSharedKey(context.Context, *btcec.PublicKey,
418+
*keychain.KeyLocator) ([sha256.Size]byte, error)
405419
}
406420

407421
var (

tapgarden/mock.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package tapgarden
33
import (
44
"bytes"
55
"context"
6+
"crypto/sha256"
67
"encoding/hex"
78
"fmt"
89
"math/rand"
@@ -972,6 +973,28 @@ func (m *MockKeyRing) ScriptKeyAt(t *testing.T, idx uint32) asset.ScriptKey {
972973
})
973974
}
974975

976+
func (m *MockKeyRing) DeriveSharedKey(_ context.Context, key *btcec.PublicKey,
977+
locator *keychain.KeyLocator) ([sha256.Size]byte, error) {
978+
979+
if locator == nil {
980+
return [32]byte{}, fmt.Errorf("locator is nil")
981+
}
982+
983+
m.RLock()
984+
defer m.RUnlock()
985+
986+
priv, ok := m.Keys[*locator]
987+
if !ok {
988+
return [32]byte{}, fmt.Errorf("script key not found at index "+
989+
"%d", locator.Index)
990+
}
991+
992+
ecdh := &keychain.PrivKeyECDH{
993+
PrivKey: priv,
994+
}
995+
return ecdh.ECDH(key)
996+
}
997+
975998
type MockGenSigner struct {
976999
KeyRing *MockKeyRing
9771000
failSigning atomic.Bool

0 commit comments

Comments
 (0)