Conner Fromknecht
3 years ago
2 changed files with 159 additions and 0 deletions
@ -0,0 +1,152 @@
|
||||
package amp |
||||
|
||||
import ( |
||||
"crypto/rand" |
||||
) |
||||
|
||||
// Sharer facilitates dynamic splitting of a root share value and derivation of
|
||||
// child preimage and hashes for individual HTLCs in an AMP payment. A sharer
|
||||
// represents a specific node in an abstract binary tree that can generate up to
|
||||
// 2^32-1 unique child preimage-hash pairs for the same share value. A node can
|
||||
// also be split into it's left and right child in the tree. The Sharer
|
||||
// guarantees that the share value of the left and right child XOR to the share
|
||||
// value of the parent. This allows larger HTLCs to split into smaller
|
||||
// subpayments, while ensuring that the reconstructed secret will exactly match
|
||||
// the root seed.
|
||||
type Sharer interface { |
||||
// Root returns the root share of the derivation tree. This is the value
|
||||
// that will be reconstructed when combining the set of all child
|
||||
// shares.
|
||||
Root() Share |
||||
|
||||
// Child derives a child preimage and child hash given a 32-bit index.
|
||||
// Passing a different index will generate a unique preimage-hash pair
|
||||
// with high probability, allowing the payment hash carried on HTLCs to
|
||||
// be refreshed without needing to modify the share value. This would
|
||||
// typically be used when an partial payment needs to be retried if it
|
||||
// encounters routine network failures.
|
||||
Child(index uint32) *Child |
||||
|
||||
// Split returns a Sharer for the left and right child of the parent
|
||||
// Sharer. XORing the share values of both sharers always yields the
|
||||
// share value of the parent. The sender should use this to recursively
|
||||
// divide payments that are too large into smaller subpayments, knowing
|
||||
// that the shares of all nodes descending from the parent will XOR to
|
||||
// the parent's share.
|
||||
Split() (Sharer, Sharer, error) |
||||
} |
||||
|
||||
// SeedSharer orchestrates the sharing of the root AMP seed along multiple
|
||||
// paths. It also supports derivation of the child payment hashes that get
|
||||
// attached to HTLCs, and the child preimages used by the receiver to settle
|
||||
// individual HTLCs in the set.
|
||||
type SeedSharer struct { |
||||
root Share |
||||
curr Share |
||||
} |
||||
|
||||
// NewSeedSharer generates a new SeedSharer instance with a seed drawn at
|
||||
// random.
|
||||
func NewSeedSharer() (*SeedSharer, error) { |
||||
var root Share |
||||
if _, err := rand.Read(root[:]); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return SeedSharerFromRoot(&root), nil |
||||
} |
||||
|
||||
// SeedSharerFromRoot instantiates a SeedSharer with an externally provided
|
||||
// seed.
|
||||
func SeedSharerFromRoot(root *Share) *SeedSharer { |
||||
return initSeedSharer(root, root) |
||||
} |
||||
|
||||
func initSeedSharer(root, curr *Share) *SeedSharer { |
||||
return &SeedSharer{ |
||||
root: *root, |
||||
curr: *curr, |
||||
} |
||||
} |
||||
|
||||
// Seed returns the sharer's seed, the primary source of entropy for deriving
|
||||
// shares of the root.
|
||||
func (s *SeedSharer) Root() Share { |
||||
return s.root |
||||
} |
||||
|
||||
// Split constructs two child Sharers whose shares sum to the parent Sharer.
|
||||
// This allows an HTLC whose payment amount could not be routed to be
|
||||
// recursively split into smaller subpayments. After splitting a sharer the
|
||||
// parent share should no longer be used, and the caller should use the Child
|
||||
// method on each to derive preimage/hash pairs for the HTLCs.
|
||||
func (s *SeedSharer) Split() (Sharer, Sharer, error) { |
||||
shareLeft, shareRight, err := split(&s.curr) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
left := initSeedSharer(&s.root, &shareLeft) |
||||
right := initSeedSharer(&s.root, &shareRight) |
||||
|
||||
return left, right, nil |
||||
} |
||||
|
||||
// Child derives a preimage/hash pair to be used for an AMP HTLC.
|
||||
// All children of s will use the same underlying share, but have unique
|
||||
// preimage and hash. This can be used to rerandomize the preimage/hash pair for
|
||||
// a given HTLC if a new route is needed.
|
||||
func (s *SeedSharer) Child(index uint32) *Child { |
||||
desc := ChildDesc{ |
||||
Share: s.curr, |
||||
Index: index, |
||||
} |
||||
|
||||
return DeriveChild(s.root, desc) |
||||
} |
||||
|
||||
// ReconstructChildren derives the set of children hashes and preimages from the
|
||||
// provided descriptors. The shares from each child descriptor are first used to
|
||||
// compute the root, afterwards the child hashes and preimages are
|
||||
// deterministically computed. For child descriptor at index i in the input,
|
||||
// it's derived child will occupy index i of the returned children.
|
||||
func ReconstructChildren(descs ...ChildDesc) []*Child { |
||||
// Recompute the root by XORing the provided shares.
|
||||
var root Share |
||||
for _, desc := range descs { |
||||
root.Xor(&root, &desc.Share) |
||||
} |
||||
|
||||
// With the root computed, derive the child hashes and preimages from
|
||||
// the child descriptors.
|
||||
children := make([]*Child, len(descs)) |
||||
for i, desc := range descs { |
||||
children[i] = DeriveChild(root, desc) |
||||
} |
||||
|
||||
return children |
||||
} |
||||
|
||||
// split splits a share into two random values, that when XOR'd reproduce the
|
||||
// original share. Given a share s, the two shares are derived as:
|
||||
// left <-$- random
|
||||
// right = parent ^ left.
|
||||
//
|
||||
// When reconstructed, we have that:
|
||||
// left ^ right = left ^ parent ^ left
|
||||
// = parent.
|
||||
func split(parent *Share) (Share, Share, error) { |
||||
// Generate a random share for the left child.
|
||||
var left Share |
||||
if _, err := rand.Read(left[:]); err != nil { |
||||
return Share{}, Share{}, err |
||||
} |
||||
|
||||
// Compute right = parent ^ left.
|
||||
var right Share |
||||
right.Xor(parent, &left) |
||||
|
||||
return left, right, nil |
||||
} |
||||
|
||||
var _ Sharer = (*SeedSharer)(nil) |
Loading…
Reference in new issue