github.com/decred/dcrlnd@v0.7.6/amp/derivation_test.go (about)

     1  package amp_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/decred/dcrlnd/amp"
     7  	"github.com/stretchr/testify/require"
     8  )
     9  
    10  type sharerTest struct {
    11  	name      string
    12  	numShares int
    13  	merge     bool
    14  }
    15  
    16  var sharerTests = []sharerTest{
    17  	{
    18  		name:      "root only",
    19  		numShares: 1,
    20  	},
    21  	{
    22  		name:      "two shares",
    23  		numShares: 2,
    24  	},
    25  	{
    26  		name:      "many shares",
    27  		numShares: 10,
    28  	},
    29  	{
    30  		name:      "merge 4 shares",
    31  		numShares: 4,
    32  		merge:     true,
    33  	},
    34  	{
    35  		name:      "merge many shares",
    36  		numShares: 20,
    37  		merge:     true,
    38  	},
    39  }
    40  
    41  // TestSharer executes the end-to-end derivation between sender and receiver,
    42  // asserting that shares are properly computed and, when reconstructed by the
    43  // receiver, produce identical child hashes and preimages as the sender.
    44  func TestSharer(t *testing.T) {
    45  	for _, test := range sharerTests {
    46  		test := test
    47  		t.Run(test.name, func(t *testing.T) {
    48  			t.Parallel()
    49  
    50  			testSharer(t, test)
    51  		})
    52  	}
    53  }
    54  
    55  func testSharer(t *testing.T, test sharerTest) {
    56  	// Construct a new sharer with a random seed.
    57  	var (
    58  		sharer amp.Sharer
    59  		err    error
    60  	)
    61  	sharer, err = amp.NewSeedSharer()
    62  	require.NoError(t, err)
    63  
    64  	// Assert that we can instantiate an equivalent root sharer using the
    65  	// root share.
    66  	root := sharer.Root()
    67  	sharerFromRoot := amp.SeedSharerFromRoot(&root)
    68  	require.Equal(t, sharer, sharerFromRoot)
    69  
    70  	// Generate numShares-1 randomized shares.
    71  	children := make([]*amp.Child, 0, test.numShares)
    72  	for i := 0; i < test.numShares-1; i++ {
    73  		var left amp.Sharer
    74  		left, sharer, err = sharer.Split()
    75  		require.NoError(t, err)
    76  
    77  		child := left.Child(0)
    78  
    79  		assertChildShare(t, child, 0)
    80  		children = append(children, child)
    81  	}
    82  
    83  	// Compute the final share and finalize the sharing.
    84  	child := sharer.Child(0)
    85  	sharer = sharer.Zero()
    86  
    87  	assertChildShare(t, child, 0)
    88  	children = append(children, child)
    89  
    90  	// If we are testing merging, merge half of the created children back
    91  	// into the sharer.
    92  	if test.merge {
    93  		for i := len(children) / 2; i < len(children); i++ {
    94  			sharer = sharer.Merge(children[i])
    95  		}
    96  		children = children[:len(children)/2]
    97  
    98  		// We must create a new last child from what we just merged
    99  		// back.
   100  		child := sharer.Child(0)
   101  
   102  		assertChildShare(t, child, 0)
   103  		children = append(children, child)
   104  	}
   105  
   106  	assertReconstruction(t, children...)
   107  }
   108  
   109  // assertChildShare checks that the child has the expected child index, and that
   110  // the child's preimage is valid for the its hash.
   111  func assertChildShare(t *testing.T, child *amp.Child, expIndex int) {
   112  	t.Helper()
   113  
   114  	require.Equal(t, uint32(expIndex), child.Index)
   115  	require.True(t, child.Preimage.Matches(child.Hash))
   116  }
   117  
   118  // assertReconstruction takes a list of children and simulates the receiver
   119  // recombining the shares, and then deriving the child preimage and hash for
   120  // each HTLC. This asserts that the receiver can always rederive the full set of
   121  // children knowing only the shares and child indexes for each.
   122  func assertReconstruction(t *testing.T, children ...*amp.Child) {
   123  	t.Helper()
   124  
   125  	// Reconstruct a child descriptor for each of the provided children.
   126  	// In practice, the receiver will only know the share and the child
   127  	// index it learns for each HTLC.
   128  	descs := make([]amp.ChildDesc, 0, len(children))
   129  	for _, child := range children {
   130  		descs = append(descs, amp.ChildDesc{
   131  			Share: child.Share,
   132  			Index: child.Index,
   133  		})
   134  	}
   135  
   136  	// Now, recombine the shares and rederive a child for each of the
   137  	// descriptors above. The resulting set of children should exactly match
   138  	// the set provided.
   139  	children2 := amp.ReconstructChildren(descs...)
   140  	require.Equal(t, children, children2)
   141  }