What changed, and why it matters
This commit is a routine code reorganization: it moves two helper functions and a constant related to Taproot channels from one internal package (channeldb) to another (chanstate), and leaves aliases in the old location so existing callers keep working. There is no change to behavior, no bug fix, and no security patch.
No security action needed. Treat as normal refactoring.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff moves DeriveMusig2Shachain, NewMusigVerificationNonce, and AbsoluteThawHeightThreshold from channeldb/channel.go into a new chanstate/taproot.go file. channeldb now re-exports these symbols as aliases pointing to chanstate. The implementation, constants, and comments are copied verbatim. No functional logic was modified.
Changed components
channeldb/channel.gochanstate/taproot.goInspect captured patch +93 / −63
diff --git a/channeldb/channel.go b/channeldb/channel.go
index eae8f2f..8985b70 100644
--- a/channeldb/channel.go
+++ b/channeldb/channel.go
@@ -2,7 +2,6 @@ package channeldb
import (
"bytes"
- "crypto/hmac"
"crypto/sha256"
"encoding/binary"
"errors"
@@ -12,7 +11,6 @@ import (
"sync"
"github.com/btcsuite/btcd/btcec/v2"
- "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
"github.com/btcsuite/btcd/btcutil/v2"
"github.com/btcsuite/btcd/chainhash/v2"
"github.com/btcsuite/btcd/wire/v2"
@@ -32,16 +30,18 @@ import (
)
const (
- // AbsoluteThawHeightThreshold is the threshold at which a thaw height
- // begins to be interpreted as an absolute block height, rather than a
- // relative one.
- AbsoluteThawHeightThreshold uint32 = 500000
-
// HTLCBlindingPointTLV is the tlv type used for storing blinding
// points with HTLCs.
HTLCBlindingPointTLV tlv.Type = 0
)
+const (
+ // AbsoluteThawHeightThreshold is the threshold at which a thaw height
+ // begins to be interpreted as an absolute block height, rather than a
+ // relative one.
+ AbsoluteThawHeightThreshold = cstate.AbsoluteThawHeightThreshold
+)
+
var (
// closedChannelBucket stores summarization information concerning
// previously open, but now closed channels.
@@ -1672,63 +1672,14 @@ func (c *OpenChannel) SecondCommitmentPoint() (*btcec.PublicKey, error) {
}
var (
- // taprootRevRootKey is the key used to derive the revocation root for
- // the taproot nonces. This is done via HMAC of the existing revocation
- // root.
- taprootRevRootKey = []byte("taproot-rev-root")
-)
-
-// DeriveMusig2Shachain derives a shachain producer for the taproot channel
-// from normal shachain revocation root.
-func DeriveMusig2Shachain(revRoot shachain.Producer) (shachain.Producer, error) { //nolint:ll
- // In order to obtain the revocation root hash to create the taproot
- // revocation, we'll encode the producer into a buffer, then use that
- // to derive the shachain root needed.
- var rootHashBuf bytes.Buffer
- if err := revRoot.Encode(&rootHashBuf); err != nil {
- return nil, fmt.Errorf("unable to encode producer: %w", err)
- }
-
- revRootHash := chainhash.HashH(rootHashBuf.Bytes())
-
- // For taproot channel types, we'll also generate a distinct shachain
- // root using the same seed information. We'll use this to generate
- // verification nonces for the channel. We'll bind with this a simple
- // hmac.
- taprootRevHmac := hmac.New(sha256.New, taprootRevRootKey)
- if _, err := taprootRevHmac.Write(revRootHash[:]); err != nil {
- return nil, err
- }
-
- taprootRevRoot := taprootRevHmac.Sum(nil)
+ // DeriveMusig2Shachain derives a shachain producer for the taproot
+ // channel from normal shachain revocation root.
+ DeriveMusig2Shachain = cstate.DeriveMusig2Shachain
- // Once we have the root, we can then generate our shachain producer
- // and from that generate the per-commitment point.
- return shachain.NewRevocationProducerFromBytes(
- taprootRevRoot,
- )
-}
-
-// NewMusigVerificationNonce generates the local or verification nonce for
-// another musig2 session. In order to permit our implementation to not have to
-// write any secret nonce state to disk, we'll use the _next_ shachain
-// pre-image as our primary randomness source. When used to generate the nonce
-// again to broadcast our commitment hte current height will be used.
-func NewMusigVerificationNonce(pubKey *btcec.PublicKey, targetHeight uint64,
- shaGen shachain.Producer) (*musig2.Nonces, error) {
-
- // Now that we know what height we need, we'll grab the shachain
- // pre-image at the target destination.
- nextPreimage, err := shaGen.AtIndex(targetHeight)
- if err != nil {
- return nil, err
- }
-
- shaChainRand := musig2.WithCustomRand(bytes.NewBuffer(nextPreimage[:]))
- pubKeyOpt := musig2.WithPublicKey(pubKey)
-
- return musig2.GenNonces(pubKeyOpt, shaChainRand)
-}
+ // NewMusigVerificationNonce generates the local or verification nonce
+ // for another musig2 session.
+ NewMusigVerificationNonce = cstate.NewMusigVerificationNonce
+)
// ChanSyncMsg returns the ChannelReestablish message that should be sent upon
// reconnection with the remote peer that we're maintaining this channel with.
diff --git a/chanstate/taproot.go b/chanstate/taproot.go
new file mode 100644
index 0000000..cfa3310
--- /dev/null
+++ b/chanstate/taproot.go
@@ -0,0 +1,79 @@
+package chanstate
+
+import (
+ "bytes"
+ "crypto/hmac"
+ "crypto/sha256"
+ "fmt"
+
+ "github.com/btcsuite/btcd/btcec/v2"
+ "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
+ "github.com/btcsuite/btcd/chainhash/v2"
+ "github.com/lightningnetwork/lnd/shachain"
+)
+
+const (
+ // AbsoluteThawHeightThreshold is the threshold at which a thaw height
+ // begins to be interpreted as an absolute block height, rather than a
+ // relative one.
+ AbsoluteThawHeightThreshold uint32 = 500000
+)
+
+var (
+ // taprootRevRootKey is the key used to derive the revocation root for
+ // the taproot nonces. This is done via HMAC of the existing revocation
+ // root.
+ taprootRevRootKey = []byte("taproot-rev-root")
+)
+
+// DeriveMusig2Shachain derives a shachain producer for the taproot channel
+// from normal shachain revocation root.
+func DeriveMusig2Shachain(revRoot shachain.Producer) (shachain.Producer, error) { //nolint:ll
+ // In order to obtain the revocation root hash to create the taproot
+ // revocation, we'll encode the producer into a buffer, then use that
+ // to derive the shachain root needed.
+ var rootHashBuf bytes.Buffer
+ if err := revRoot.Encode(&rootHashBuf); err != nil {
+ return nil, fmt.Errorf("unable to encode producer: %w", err)
+ }
+
+ revRootHash := chainhash.HashH(rootHashBuf.Bytes())
+
+ // For taproot channel types, we'll also generate a distinct shachain
+ // root using the same seed information. We'll use this to generate
+ // verification nonces for the channel. We'll bind with this a simple
+ // hmac.
+ taprootRevHmac := hmac.New(sha256.New, taprootRevRootKey)
+ if _, err := taprootRevHmac.Write(revRootHash[:]); err != nil {
+ return nil, err
+ }
+
+ taprootRevRoot := taprootRevHmac.Sum(nil)
+
+ // Once we have the root, we can then generate our shachain producer
+ // and from that generate the per-commitment point.
+ return shachain.NewRevocationProducerFromBytes(
+ taprootRevRoot,
+ )
+}
+
+// NewMusigVerificationNonce generates the local or verification nonce for
+// another musig2 session. In order to permit our implementation to not have to
+// write any secret nonce state to disk, we'll use the _next_ shachain
+// pre-image as our primary randomness source. When used to generate the nonce
+// again to broadcast our commitment hte current height will be used.
+func NewMusigVerificationNonce(pubKey *btcec.PublicKey, targetHeight uint64,
+ shaGen shachain.Producer) (*musig2.Nonces, error) {
+
+ // Now that we know what height we need, we'll grab the shachain
+ // pre-image at the target destination.
+ nextPreimage, err := shaGen.AtIndex(targetHeight)
+ if err != nil {
+ return nil, err
+ }
+
+ shaChainRand := musig2.WithCustomRand(bytes.NewBuffer(nextPreimage[:]))
+ pubKeyOpt := musig2.WithPublicKey(pubKey)
+
+ return musig2.GenNonces(pubKeyOpt, shaChainRand)
+}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.