lnwallet: modify elkrem root derivation, derive from root HD seed
This commit modifies the elkrem root derivation for each newly created channel. First a master elkrem root is derived from the rood HD seed generated from private wallet data. Next, a HKDF is used with the secret being the master elkrem root.
This commit is contained in:
parent
564316a846
commit
99fdb3a3a9
@ -743,12 +743,13 @@ func DeriveRevocationPrivKey(commitPrivKey *btcec.PrivateKey,
|
|||||||
//
|
//
|
||||||
// [1]: https://eprint.iacr.org/2010/264.pdf
|
// [1]: https://eprint.iacr.org/2010/264.pdf
|
||||||
// [2]: https://tools.ietf.org/html/rfc5869
|
// [2]: https://tools.ietf.org/html/rfc5869
|
||||||
func deriveElkremRoot(localMultiSigKey *btcec.PrivateKey,
|
func deriveElkremRoot(elkremDerivationRoot *btcec.PrivateKey,
|
||||||
|
localMultiSigKey *btcec.PublicKey,
|
||||||
remoteMultiSigKey *btcec.PublicKey) wire.ShaHash {
|
remoteMultiSigKey *btcec.PublicKey) wire.ShaHash {
|
||||||
|
|
||||||
secret := localMultiSigKey.Serialize()
|
secret := elkremDerivationRoot.Serialize()
|
||||||
salt := remoteMultiSigKey.SerializeCompressed()
|
salt := localMultiSigKey.SerializeCompressed()
|
||||||
info := []byte("elkrem")
|
info := remoteMultiSigKey.SerializeCompressed()
|
||||||
|
|
||||||
rootReader := hkdf.New(sha256.New, secret, salt, info)
|
rootReader := hkdf.New(sha256.New, secret, salt, info)
|
||||||
|
|
||||||
|
@ -29,6 +29,10 @@ const (
|
|||||||
// The size of the buffered queue of requests to the wallet from the
|
// The size of the buffered queue of requests to the wallet from the
|
||||||
// outside word.
|
// outside word.
|
||||||
msgBufferSize = 100
|
msgBufferSize = 100
|
||||||
|
|
||||||
|
// elkremRootIndex is the top level HD key index from which secrets
|
||||||
|
// used to generate elkrem roots should be derived from.
|
||||||
|
elkremRootIndex = hdkeychain.HardenedKeyStart + 1
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -246,6 +250,9 @@ type LightningWallet struct {
|
|||||||
// * getrawtransaction -> verify proof of channel links
|
// * getrawtransaction -> verify proof of channel links
|
||||||
// * gettxout -> verify inputs to funding tx exist and are unspent
|
// * gettxout -> verify inputs to funding tx exist and are unspent
|
||||||
rpc *chain.RPCClient
|
rpc *chain.RPCClient
|
||||||
|
// rootKey is the root HD key dervied from a WalletController private
|
||||||
|
// key. This rootKey is used to derive all LN specific secrets.
|
||||||
|
rootKey *hdkeychain.ExtendedKey
|
||||||
|
|
||||||
// All messages to the wallet are to be sent accross this channel.
|
// All messages to the wallet are to be sent accross this channel.
|
||||||
msgChan chan interface{}
|
msgChan chan interface{}
|
||||||
@ -294,6 +301,9 @@ func NewLightningWallet(config *Config, cdb *channeldb.DB,
|
|||||||
|
|
||||||
loader := btcwallet.NewLoader(config.NetParams, netDir)
|
loader := btcwallet.NewLoader(config.NetParams, netDir)
|
||||||
walletExists, err := loader.WalletExists()
|
walletExists, err := loader.WalletExists()
|
||||||
|
// Fetch the root derivation key from the wallet's HD chain. We'll use
|
||||||
|
// this to generate specific Lightning related secrets on the fly.
|
||||||
|
rootKey, err := wallet.FetchRootKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -359,6 +369,7 @@ func NewLightningWallet(config *Config, cdb *channeldb.DB,
|
|||||||
cfg: config,
|
cfg: config,
|
||||||
fundingLimbo: make(map[uint64]*ChannelReservation),
|
fundingLimbo: make(map[uint64]*ChannelReservation),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
|
rootKey: rootMasterKey,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -769,11 +780,17 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
|
|||||||
pendingReservation.partialState.RemoteElkrem = e
|
pendingReservation.partialState.RemoteElkrem = e
|
||||||
pendingReservation.partialState.TheirCurrentRevocation = theirContribution.RevocationKey
|
pendingReservation.partialState.TheirCurrentRevocation = theirContribution.RevocationKey
|
||||||
|
|
||||||
|
masterElkremRoot, err := l.deriveMasterElkremRoot()
|
||||||
|
if err != nil {
|
||||||
|
req.err <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Now that we have their commitment key, we can create the revocation
|
// Now that we have their commitment key, we can create the revocation
|
||||||
// key for the first version of our commitment transaction. To do so,
|
// key for the first version of our commitment transaction. To do so,
|
||||||
// we'll first create our elkrem root, then grab the first pre-iamge
|
// we'll first create our elkrem root, then grab the first pre-iamge
|
||||||
// from it.
|
// from it.
|
||||||
elkremRoot := deriveElkremRoot(ourKey, theirKey)
|
elkremRoot := deriveElkremRoot(masterElkremRoot, ourKey, theirKey)
|
||||||
elkremSender := elkrem.NewElkremSender(elkremRoot)
|
elkremSender := elkrem.NewElkremSender(elkremRoot)
|
||||||
pendingReservation.partialState.LocalElkrem = elkremSender
|
pendingReservation.partialState.LocalElkrem = elkremSender
|
||||||
firstPreimage, err := elkremSender.AtIndex(0)
|
firstPreimage, err := elkremSender.AtIndex(0)
|
||||||
@ -881,9 +898,15 @@ func (l *LightningWallet) handleSingleContribution(req *addSingleContributionMsg
|
|||||||
}
|
}
|
||||||
pendingReservation.partialState.FundingRedeemScript = redeemScript
|
pendingReservation.partialState.FundingRedeemScript = redeemScript
|
||||||
|
|
||||||
|
masterElkremRoot, err := l.deriveMasterElkremRoot()
|
||||||
|
if err != nil {
|
||||||
|
req.err <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Now that we know their commitment key, we can create the revocation
|
// Now that we know their commitment key, we can create the revocation
|
||||||
// key for our version of the initial commitment transaction.
|
// key for our version of the initial commitment transaction.
|
||||||
elkremRoot := deriveElkremRoot(ourKey, theirKey)
|
elkremRoot := deriveElkremRoot(masterElkremRoot, ourKey, theirKey)
|
||||||
elkremSender := elkrem.NewElkremSender(elkremRoot)
|
elkremSender := elkrem.NewElkremSender(elkremRoot)
|
||||||
firstPreimage, err := elkremSender.AtIndex(0)
|
firstPreimage, err := elkremSender.AtIndex(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1394,16 +1417,18 @@ func (l *LightningWallet) selectCoinsAndChange(feeRate uint64, amt btcutil.Amoun
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type WaddrmgrEncryptorDecryptor struct {
|
// deriveMasterElkremRoot derives the private key which serves as the master
|
||||||
M *waddrmgr.Manager
|
// elkrem root. This master secret is used as the secret input to a HKDF to
|
||||||
|
// generate elkrem secrets based on random, but public data.
|
||||||
|
func (l *LightningWallet) deriveMasterElkremRoot() (*btcec.PrivateKey, error) {
|
||||||
|
masterElkremRoot, err := l.rootKey.Child(elkremRootIndex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return masterElkremRoot.ECPrivKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WaddrmgrEncryptorDecryptor) Encrypt(p []byte) ([]byte, error) {
|
|
||||||
return w.M.Encrypt(waddrmgr.CKTPrivate, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WaddrmgrEncryptorDecryptor) Decrypt(c []byte) ([]byte, error) {
|
|
||||||
return w.M.Decrypt(waddrmgr.CKTPrivate, c)
|
|
||||||
// selectInputs selects a slice of inputs necessary to meet the specified
|
// selectInputs selects a slice of inputs necessary to meet the specified
|
||||||
// selection amount. If input selectino is unable to suceed to to insuffcient
|
// selection amount. If input selectino is unable to suceed to to insuffcient
|
||||||
// funds, a non-nil error is returned. Additionally, the total amount of the
|
// funds, a non-nil error is returned. Additionally, the total amount of the
|
||||||
@ -1440,8 +1465,6 @@ func selectInputs(amt btcutil.Amount, coins []*Utxo) (btcutil.Amount, []*wire.Ou
|
|||||||
return satSelected, selectedUtxos, nil
|
return satSelected, selectedUtxos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WaddrmgrEncryptorDecryptor) OverheadSize() uint32 {
|
|
||||||
return 24
|
|
||||||
// coinSelect attemps to select a sufficient amount of coins, including a
|
// coinSelect attemps to select a sufficient amount of coins, including a
|
||||||
// change output to fund amt satoshis, adhearing to the specified fee rate. The
|
// change output to fund amt satoshis, adhearing to the specified fee rate. The
|
||||||
// specified fee rate should be expressed in sat/byte for coin selection to
|
// specified fee rate should be expressed in sat/byte for coin selection to
|
||||||
|
Loading…
Reference in New Issue
Block a user