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:
Olaoluwa Osuntokun 2016-08-12 15:43:16 -07:00
parent 564316a846
commit 99fdb3a3a9
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
2 changed files with 40 additions and 16 deletions

@ -743,12 +743,13 @@ func DeriveRevocationPrivKey(commitPrivKey *btcec.PrivateKey,
//
// [1]: https://eprint.iacr.org/2010/264.pdf
// [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 {
secret := localMultiSigKey.Serialize()
salt := remoteMultiSigKey.SerializeCompressed()
info := []byte("elkrem")
secret := elkremDerivationRoot.Serialize()
salt := localMultiSigKey.SerializeCompressed()
info := remoteMultiSigKey.SerializeCompressed()
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
// outside word.
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 (
@ -246,6 +250,9 @@ type LightningWallet struct {
// * getrawtransaction -> verify proof of channel links
// * gettxout -> verify inputs to funding tx exist and are unspent
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.
msgChan chan interface{}
@ -294,6 +301,9 @@ func NewLightningWallet(config *Config, cdb *channeldb.DB,
loader := btcwallet.NewLoader(config.NetParams, netDir)
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 {
return nil, err
}
@ -359,6 +369,7 @@ func NewLightningWallet(config *Config, cdb *channeldb.DB,
cfg: config,
fundingLimbo: make(map[uint64]*ChannelReservation),
quit: make(chan struct{}),
rootKey: rootMasterKey,
}, nil
}
@ -769,11 +780,17 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
pendingReservation.partialState.RemoteElkrem = e
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
// 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
// from it.
elkremRoot := deriveElkremRoot(ourKey, theirKey)
elkremRoot := deriveElkremRoot(masterElkremRoot, ourKey, theirKey)
elkremSender := elkrem.NewElkremSender(elkremRoot)
pendingReservation.partialState.LocalElkrem = elkremSender
firstPreimage, err := elkremSender.AtIndex(0)
@ -881,9 +898,15 @@ func (l *LightningWallet) handleSingleContribution(req *addSingleContributionMsg
}
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
// key for our version of the initial commitment transaction.
elkremRoot := deriveElkremRoot(ourKey, theirKey)
elkremRoot := deriveElkremRoot(masterElkremRoot, ourKey, theirKey)
elkremSender := elkrem.NewElkremSender(elkremRoot)
firstPreimage, err := elkremSender.AtIndex(0)
if err != nil {
@ -1394,16 +1417,18 @@ func (l *LightningWallet) selectCoinsAndChange(feeRate uint64, amt btcutil.Amoun
return nil
}
type WaddrmgrEncryptorDecryptor struct {
M *waddrmgr.Manager
// deriveMasterElkremRoot derives the private key which serves as the master
// 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
// 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
@ -1440,8 +1465,6 @@ func selectInputs(amt btcutil.Amount, coins []*Utxo) (btcutil.Amount, []*wire.Ou
return satSelected, selectedUtxos, nil
}
func (w *WaddrmgrEncryptorDecryptor) OverheadSize() uint32 {
return 24
// coinSelect attemps to select a sufficient amount of coins, including a
// 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