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 }