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

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 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 {
3✔
117
        var curr Share
3✔
118
        curr.Xor(&s.curr, &child.Share)
3✔
119

3✔
120
        sharer := initSeedSharer(&s.root, &curr)
3✔
121
        return sharer
3✔
122
}
3✔
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