• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 15736109134

18 Jun 2025 02:46PM UTC coverage: 58.197% (-10.1%) from 68.248%
15736109134

Pull #9752

github

web-flow
Merge d2634a68c into 31c74f20f
Pull Request #9752: routerrpc: reject payment to invoice that don't have payment secret or blinded paths

6 of 13 new or added lines in 2 files covered. (46.15%)

28331 existing lines in 455 files now uncovered.

97860 of 168153 relevant lines covered (58.2%)

1.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.57
/amp/sharer.go
1
package amp
2

3
import (
4
        "crypto/rand"
5
        "fmt"
6
)
7

8
// zeroShare is the all-zero 32-byte share.
9
var zeroShare = Share{}
10

11
// Sharer facilitates dynamic splitting of a root share value and derivation of
12
// child preimage and hashes for individual HTLCs in an AMP payment. A sharer
13
// represents a specific node in an abstract binary tree that can generate up to
14
// 2^32-1 unique child preimage-hash pairs for the same share value. A node can
15
// also be split into it's left and right child in the tree. The Sharer
16
// guarantees that the share value of the left and right child XOR to the share
17
// value of the parent. This allows larger HTLCs to split into smaller
18
// subpayments, while ensuring that the reconstructed secret will exactly match
19
// the root seed.
20
type Sharer interface {
21
        // Root returns the root share of the derivation tree. This is the value
22
        // that will be reconstructed when combining the set of all child
23
        // shares.
24
        Root() Share
25

26
        // Child derives a child preimage and child hash given a 32-bit index.
27
        // Passing a different index will generate a unique preimage-hash pair
28
        // with high probability, allowing the payment hash carried on HTLCs to
29
        // be refreshed without needing to modify the share value. This would
30
        // typically be used when an partial payment needs to be retried if it
31
        // encounters routine network failures.
32
        Child(index uint32) *Child
33

34
        // Split returns a Sharer for the left and right child of the parent
35
        // Sharer. XORing the share values of both sharers always yields the
36
        // share value of the parent. The sender should use this to recursively
37
        // divide payments that are too large into smaller subpayments, knowing
38
        // that the shares of all nodes descending from the parent will XOR to
39
        // the parent's share.
40
        Split() (Sharer, Sharer, error)
41

42
        // Merge takes the given Child and "merges" it into the Sharer by
43
        // XOR-ing its share with the Sharer's current share.
44
        Merge(*Child) Sharer
45

46
        // Zero returns a a new "zero Sharer" that has its current share set to
47
        // zero, while keeping the root share. Merging a Child from the
48
        // original Sharer into this zero-Sharer gives back the original
49
        // Sharer.
50
        Zero() Sharer
51
}
52

53
// SeedSharer orchestrates the sharing of the root AMP seed along multiple
54
// paths. It also supports derivation of the child payment hashes that get
55
// attached to HTLCs, and the child preimages used by the receiver to settle
56
// individual HTLCs in the set.
57
type SeedSharer struct {
58
        root Share
59
        curr Share
60
}
61

62
// NewSeedSharer generates a new SeedSharer instance with a seed drawn at
63
// random.
UNCOV
64
func NewSeedSharer() (*SeedSharer, error) {
×
UNCOV
65
        var root Share
×
UNCOV
66
        if _, err := rand.Read(root[:]); err != nil {
×
67
                return nil, err
×
68
        }
×
69

UNCOV
70
        return SeedSharerFromRoot(&root), nil
×
71
}
72

73
// SeedSharerFromRoot instantiates a SeedSharer with an externally provided
74
// seed.
75
func SeedSharerFromRoot(root *Share) *SeedSharer {
3✔
76
        return initSeedSharer(root, root)
3✔
77
}
3✔
78

79
func initSeedSharer(root, curr *Share) *SeedSharer {
3✔
80
        return &SeedSharer{
3✔
81
                root: *root,
3✔
82
                curr: *curr,
3✔
83
        }
3✔
84
}
3✔
85

86
// Seed returns the sharer's seed, the primary source of entropy for deriving
87
// shares of the root.
UNCOV
88
func (s *SeedSharer) Root() Share {
×
UNCOV
89
        return s.root
×
UNCOV
90
}
×
91

92
// Split constructs two child Sharers whose shares sum to the parent Sharer.
93
// This allows an HTLC whose payment amount could not be routed to be
94
// recursively split into smaller subpayments. After splitting a sharer the
95
// parent share should no longer be used, and the caller should use the Child
96
// method on each to derive preimage/hash pairs for the HTLCs.
97
func (s *SeedSharer) Split() (Sharer, Sharer, error) {
3✔
98
        // We cannot split the zero-Sharer.
3✔
99
        if s.curr == zeroShare {
3✔
100
                return nil, nil, fmt.Errorf("cannot split zero-Sharer")
×
101
        }
×
102

103
        shareLeft, shareRight, err := split(&s.curr)
3✔
104
        if err != nil {
3✔
105
                return nil, nil, err
×
106
        }
×
107

108
        left := initSeedSharer(&s.root, &shareLeft)
3✔
109
        right := initSeedSharer(&s.root, &shareRight)
3✔
110

3✔
111
        return left, right, nil
3✔
112
}
113

114
// Merge takes the given Child and "merges" it into the Sharer by XOR-ing its
115
// share with the Sharer's current share.
116
func (s *SeedSharer) Merge(child *Child) Sharer {
1✔
117
        var curr Share
1✔
118
        curr.Xor(&s.curr, &child.Share)
1✔
119

1✔
120
        sharer := initSeedSharer(&s.root, &curr)
1✔
121
        return sharer
1✔
122
}
1✔
123

124
// Zero returns a a new "zero Sharer" that has its current share set to zero,
125
// while keeping the root share. Merging a Child from the original Sharer into
126
// this zero-Sharer gives back the original Sharer.
127
func (s *SeedSharer) Zero() Sharer {
3✔
128
        return initSeedSharer(&s.root, &zeroShare)
3✔
129
}
3✔
130

131
// Child derives a preimage/hash pair to be used for an AMP HTLC.
132
// All children of s will use the same underlying share, but have unique
133
// preimage and hash. This can be used to rerandomize the preimage/hash pair for
134
// a given HTLC if a new route is needed.
135
func (s *SeedSharer) Child(index uint32) *Child {
3✔
136
        desc := ChildDesc{
3✔
137
                Share: s.curr,
3✔
138
                Index: index,
3✔
139
        }
3✔
140

3✔
141
        return DeriveChild(s.root, desc)
3✔
142
}
3✔
143

144
// ReconstructChildren derives the set of children hashes and preimages from the
145
// provided descriptors. The shares from each child descriptor are first used to
146
// compute the root, afterwards the child hashes and preimages are
147
// deterministically computed. For child descriptor at index i in the input,
148
// it's derived child will occupy index i of the returned children.
149
func ReconstructChildren(descs ...ChildDesc) []*Child {
3✔
150
        // Recompute the root by XORing the provided shares.
3✔
151
        var root Share
3✔
152
        for _, desc := range descs {
6✔
153
                root.Xor(&root, &desc.Share)
3✔
154
        }
3✔
155

156
        // With the root computed, derive the child hashes and preimages from
157
        // the child descriptors.
158
        children := make([]*Child, len(descs))
3✔
159
        for i, desc := range descs {
6✔
160
                children[i] = DeriveChild(root, desc)
3✔
161
        }
3✔
162

163
        return children
3✔
164
}
165

166
// split splits a share into two random values, that when XOR'd reproduce the
167
// original share. Given a share s, the two shares are derived as:
168
//
169
//        left <-$- random
170
//        right = parent ^ left.
171
//
172
// When reconstructed, we have that:
173
//
174
//        left ^ right = left ^ parent ^ left
175
//                     = parent.
176
func split(parent *Share) (Share, Share, error) {
3✔
177
        // Generate a random share for the left child.
3✔
178
        var left Share
3✔
179
        if _, err := rand.Read(left[:]); err != nil {
3✔
180
                return Share{}, Share{}, err
×
181
        }
×
182

183
        // Compute right = parent ^ left.
184
        var right Share
3✔
185
        right.Xor(parent, &left)
3✔
186

3✔
187
        return left, right, nil
3✔
188
}
189

190
var _ Sharer = (*SeedSharer)(nil)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc