github.com/decred/dcrlnd@v0.7.6/shachain/element_test.go (about)

     1  package shachain
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  
     7  	"github.com/go-errors/errors"
     8  )
     9  
    10  // bitsToIndex is a helper function which takes 'n' last bits as input and
    11  // create shachain index.
    12  // Example:
    13  //
    14  //	Input: 0,1,1,0,0
    15  //	Output: 0b000000000000000000000000000000000000000[01100] == 12
    16  func bitsToIndex(bs ...uint64) (index, error) {
    17  	if len(bs) > 64 {
    18  		return 0, errors.New("number of elements should be lower then" +
    19  			" 64")
    20  	}
    21  
    22  	var res uint64
    23  	for i, e := range bs {
    24  		if e != 1 && e != 0 {
    25  			return 0, errors.New("wrong element, should be '0' or" +
    26  				" '1'")
    27  		}
    28  
    29  		res += e * 1 << uint(len(bs)-i-1)
    30  	}
    31  
    32  	return index(res), nil
    33  }
    34  
    35  type deriveTest struct {
    36  	name       string
    37  	from       index
    38  	to         index
    39  	position   []uint8
    40  	shouldFail bool
    41  }
    42  
    43  func generateTests(t *testing.T) []deriveTest {
    44  	var (
    45  		tests []deriveTest
    46  		from  index
    47  		to    index
    48  		err   error
    49  	)
    50  
    51  	from, err = bitsToIndex(0)
    52  	if err != nil {
    53  		t.Fatalf("can't generate from index: %v", err)
    54  	}
    55  	to, err = bitsToIndex(0)
    56  	if err != nil {
    57  		t.Fatalf("can't generate from index: %v", err)
    58  	}
    59  	tests = append(tests, deriveTest{
    60  		name:       "zero 'from' 'to'",
    61  		from:       from,
    62  		to:         to,
    63  		position:   nil,
    64  		shouldFail: false,
    65  	})
    66  
    67  	from, err = bitsToIndex(0, 1, 0, 0)
    68  	if err != nil {
    69  		t.Fatalf("can't generate from index: %v", err)
    70  	}
    71  	to, err = bitsToIndex(0, 1, 0, 0)
    72  	if err != nil {
    73  		t.Fatalf("can't generate from index: %v", err)
    74  	}
    75  	tests = append(tests, deriveTest{
    76  		name:       "same indexes #1",
    77  		from:       from,
    78  		to:         to,
    79  		position:   nil,
    80  		shouldFail: false,
    81  	})
    82  
    83  	from, err = bitsToIndex(1)
    84  	if err != nil {
    85  		t.Fatalf("can't generate from index: %v", err)
    86  	}
    87  	to, err = bitsToIndex(0)
    88  	if err != nil {
    89  		t.Fatalf("can't generate from index: %v", err)
    90  	}
    91  	tests = append(tests, deriveTest{
    92  		name:       "same indexes #2",
    93  		from:       from,
    94  		to:         to,
    95  		shouldFail: true,
    96  	})
    97  
    98  	from, err = bitsToIndex(0, 0, 0, 0)
    99  	if err != nil {
   100  		t.Fatalf("can't generate from index: %v", err)
   101  	}
   102  	to, err = bitsToIndex(0, 0, 1, 0)
   103  	if err != nil {
   104  		t.Fatalf("can't generate from index: %v", err)
   105  	}
   106  	tests = append(tests, deriveTest{
   107  		name:       "test seed 'from'",
   108  		from:       from,
   109  		to:         to,
   110  		position:   []uint8{1},
   111  		shouldFail: false,
   112  	})
   113  
   114  	from, err = bitsToIndex(1, 1, 0, 0)
   115  	if err != nil {
   116  		t.Fatalf("can't generate from index: %v", err)
   117  	}
   118  	to, err = bitsToIndex(0, 1, 0, 0)
   119  	if err != nil {
   120  		t.Fatalf("can't generate from index: %v", err)
   121  	}
   122  	tests = append(tests, deriveTest{
   123  		name:       "not the same indexes",
   124  		from:       from,
   125  		to:         to,
   126  		shouldFail: true,
   127  	})
   128  
   129  	from, err = bitsToIndex(1, 0, 1, 0)
   130  	if err != nil {
   131  		t.Fatalf("can't generate from index: %v", err)
   132  	}
   133  	to, err = bitsToIndex(1, 0, 0, 0)
   134  	if err != nil {
   135  		t.Fatalf("can't generate from index: %v", err)
   136  	}
   137  	tests = append(tests, deriveTest{
   138  		name:       "'from' index greater then 'to' index",
   139  		from:       from,
   140  		to:         to,
   141  		shouldFail: true,
   142  	})
   143  
   144  	from, err = bitsToIndex(1)
   145  	if err != nil {
   146  		t.Fatalf("can't generate from index: %v", err)
   147  	}
   148  	to, err = bitsToIndex(1)
   149  	if err != nil {
   150  		t.Fatalf("can't generate from index: %v", err)
   151  	}
   152  	tests = append(tests, deriveTest{
   153  		name:       "zero number trailing zeros",
   154  		from:       from,
   155  		to:         to,
   156  		position:   nil,
   157  		shouldFail: false,
   158  	})
   159  
   160  	return tests
   161  }
   162  
   163  // TestDeriveIndex check the correctness of index derive function by testing
   164  // the index corner cases.
   165  func TestDeriveIndex(t *testing.T) {
   166  	t.Parallel()
   167  
   168  	for _, test := range generateTests(t) {
   169  		pos, err := test.from.deriveBitTransformations(test.to)
   170  		if err != nil {
   171  			if !test.shouldFail {
   172  				t.Fatalf("Failed (%v): %v", test.name, err)
   173  			}
   174  		} else {
   175  			if test.shouldFail {
   176  				t.Fatalf("Failed (%v): test should failed "+
   177  					"but it's not", test.name)
   178  			}
   179  
   180  			if !reflect.DeepEqual(pos, test.position) {
   181  				t.Fatalf("Failed(%v): position is wrong real:"+
   182  					"%v expected:%v", test.name, pos, test.position)
   183  			}
   184  		}
   185  
   186  		t.Logf("Passed: %v", test.name)
   187  
   188  	}
   189  }
   190  
   191  // deriveElementTests encodes the test vectors specified in BOLT-03,
   192  // Appendix D, Generation Tests.
   193  var deriveElementTests = []struct {
   194  	name       string
   195  	index      index
   196  	output     string
   197  	seed       string
   198  	shouldFail bool
   199  }{
   200  	{
   201  		name:       "generate_from_seed 0 final node",
   202  		seed:       "0000000000000000000000000000000000000000000000000000000000000000",
   203  		index:      0xffffffffffff,
   204  		output:     "02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148",
   205  		shouldFail: false,
   206  	},
   207  	{
   208  		name:       "generate_from_seed FF final node",
   209  		seed:       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
   210  		index:      0xffffffffffff,
   211  		output:     "7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc",
   212  		shouldFail: false,
   213  	},
   214  	{
   215  		name:       "generate_from_seed FF alternate bits 1",
   216  		index:      0xaaaaaaaaaaa,
   217  		output:     "56f4008fb007ca9acf0e15b054d5c9fd12ee06cea347914ddbaed70d1c13a528",
   218  		seed:       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
   219  		shouldFail: false,
   220  	},
   221  	{
   222  		name:       "generate_from_seed FF alternate bits 2",
   223  		index:      0x555555555555,
   224  		output:     "9015daaeb06dba4ccc05b91b2f73bd54405f2be9f217fbacd3c5ac2e62327d31",
   225  		seed:       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
   226  		shouldFail: false,
   227  	},
   228  	{
   229  		name:       "generate_from_seed 01 last nontrivial node",
   230  		index:      1,
   231  		output:     "915c75942a26bb3a433a8ce2cb0427c29ec6c1775cfc78328b57f6ba7bfeaa9c",
   232  		seed:       "0101010101010101010101010101010101010101010101010101010101010101",
   233  		shouldFail: false,
   234  	},
   235  }
   236  
   237  // TestSpecificationDeriveElement is used to check the consistency with
   238  // specification hash derivation function.
   239  func TestSpecificationDeriveElement(t *testing.T) {
   240  	t.Parallel()
   241  
   242  	for _, test := range deriveElementTests {
   243  		// Generate seed element.
   244  		element, err := newElementFromStr(test.seed, rootIndex)
   245  		if err != nil {
   246  			t.Fatal(err)
   247  		}
   248  
   249  		// Derive element by index.
   250  		result, err := element.derive(test.index)
   251  		if err != nil {
   252  			if !test.shouldFail {
   253  				t.Fatalf("Failed (%v): %v", test.name, err)
   254  			}
   255  		} else {
   256  			if test.shouldFail {
   257  				t.Fatalf("Failed (%v): test should failed "+
   258  					"but it's not", test.name)
   259  			}
   260  
   261  			// Generate element which we should get after derivation.
   262  			output, err := newElementFromStr(test.output, test.index)
   263  			if err != nil {
   264  				t.Fatal(err)
   265  			}
   266  
   267  			// Check that they are equal.
   268  			if !result.isEqual(output) {
   269  				t.Fatalf("Failed (%v): hash is wrong, real:"+
   270  					"%x expected:%x", test.name,
   271  					result.hash, output.hash)
   272  			}
   273  		}
   274  
   275  		t.Logf("Passed (%v)", test.name)
   276  	}
   277  }