amp: add Merge and Zero to Sharer interface

This commit is contained in:
Johan T. Halseth 2021-04-08 12:08:06 +02:00
parent e1399fb1ec
commit c1e82e534d
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
2 changed files with 64 additions and 0 deletions

View File

@ -10,6 +10,7 @@ import (
type sharerTest struct { type sharerTest struct {
name string name string
numShares int numShares int
merge bool
} }
var sharerTests = []sharerTest{ var sharerTests = []sharerTest{
@ -25,6 +26,16 @@ var sharerTests = []sharerTest{
name: "many shares", name: "many shares",
numShares: 10, numShares: 10,
}, },
{
name: "merge 4 shares",
numShares: 4,
merge: true,
},
{
name: "merge many shares",
numShares: 20,
merge: true,
},
} }
// TestSharer executes the end-to-end derivation between sender and receiver, // TestSharer executes the end-to-end derivation between sender and receiver,
@ -71,10 +82,27 @@ func testSharer(t *testing.T, test sharerTest) {
// Compute the final share and finalize the sharing. // Compute the final share and finalize the sharing.
child := sharer.Child(0) child := sharer.Child(0)
sharer = sharer.Zero()
assertChildShare(t, child, 0) assertChildShare(t, child, 0)
children = append(children, child) children = append(children, child)
// If we are testing merging, merge half of the created children back
// into the sharer.
if test.merge {
for i := len(children) / 2; i < len(children); i++ {
sharer = sharer.Merge(children[i])
}
children = children[:len(children)/2]
// We must create a new last child from what we just merged
// back.
child := sharer.Child(0)
assertChildShare(t, child, 0)
children = append(children, child)
}
assertReconstruction(t, children...) assertReconstruction(t, children...)
} }

View File

@ -2,8 +2,12 @@ package amp
import ( import (
"crypto/rand" "crypto/rand"
"fmt"
) )
// zeroShare is the all-zero 32-byte share.
var zeroShare = Share{}
// Sharer facilitates dynamic splitting of a root share value and derivation of // 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 // 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 // represents a specific node in an abstract binary tree that can generate up to
@ -34,6 +38,16 @@ type Sharer interface {
// that the shares of all nodes descending from the parent will XOR to // that the shares of all nodes descending from the parent will XOR to
// the parent's share. // the parent's share.
Split() (Sharer, Sharer, error) Split() (Sharer, Sharer, error)
// Merge takes the given Child and "merges" it into the Sharer by
// XOR-ing its share with the Sharer's current share.
Merge(*Child) Sharer
// Zero returns a a new "zero Sharer" that has its current share set to
// zero, while keeping the root share. Merging a Child from the
// original Sharer into this zero-Sharer gives back the original
// Sharer.
Zero() Sharer
} }
// SeedSharer orchestrates the sharing of the root AMP seed along multiple // SeedSharer orchestrates the sharing of the root AMP seed along multiple
@ -81,6 +95,11 @@ func (s *SeedSharer) Root() Share {
// parent share should no longer be used, and the caller should use the Child // 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. // method on each to derive preimage/hash pairs for the HTLCs.
func (s *SeedSharer) Split() (Sharer, Sharer, error) { func (s *SeedSharer) Split() (Sharer, Sharer, error) {
// We cannot split the zero-Sharer.
if s.curr == zeroShare {
return nil, nil, fmt.Errorf("cannot split zero-Sharer")
}
shareLeft, shareRight, err := split(&s.curr) shareLeft, shareRight, err := split(&s.curr)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -92,6 +111,23 @@ func (s *SeedSharer) Split() (Sharer, Sharer, error) {
return left, right, nil return left, right, nil
} }
// Merge takes the given Child and "merges" it into the Sharer by XOR-ing its
// share with the Sharer's current share.
func (s *SeedSharer) Merge(child *Child) Sharer {
var curr Share
curr.Xor(&s.curr, &child.Share)
sharer := initSeedSharer(&s.root, &curr)
return sharer
}
// Zero returns a a new "zero Sharer" that has its current share set to zero,
// while keeping the root share. Merging a Child from the original Sharer into
// this zero-Sharer gives back the original Sharer.
func (s *SeedSharer) Zero() Sharer {
return initSeedSharer(&s.root, &zeroShare)
}
// Child derives a preimage/hash pair to be used for an AMP HTLC. // 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 // 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 // preimage and hash. This can be used to rerandomize the preimage/hash pair for