github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/merkler/stacked_test.go (about)

     1  // Copyright 2020 Insolar Network Ltd.
     2  // All rights reserved.
     3  // This material is licensed under the Insolar License version 1.0,
     4  // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md.
     5  
     6  package merkler
     7  
     8  import (
     9  	"fmt"
    10  	"math"
    11  	"math/bits"
    12  	"testing"
    13  
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/insolar/vanilla/cryptkit"
    17  	"github.com/insolar/vanilla/longbits"
    18  )
    19  
    20  func TestStackedCalculator_Unbalanced_AllEntries(t *testing.T) {
    21  	md := NewForkingCalculator(xorPairDigester{}, cryptkit.Digest{})
    22  
    23  	for bit := uint64(1); bit != 0; bit <<= 1 {
    24  		md.AddNext(newBits64(bit))
    25  		require.Equal(t, bit<<1-1, md.ForkSequence().FinishSequence().FoldToUint64())
    26  	}
    27  	require.Equal(t, 64, md.Count())
    28  	require.Equal(t, uint64(math.MaxUint64), md.ForkSequence().FinishSequence().FoldToUint64())
    29  
    30  	md2 := md.ForkSequence()
    31  	for bit := uint64(1) << 63; bit != 0; bit >>= 1 {
    32  		md2.AddNext(newBits64(bit))
    33  		require.Equal(t, bit-1, md2.ForkSequence().FinishSequence().FoldToUint64())
    34  	}
    35  	require.Equal(t, uint64(0), md2.FinishSequence().FoldToUint64())
    36  
    37  	for bit := uint64(1); bit != 0; bit <<= 1 {
    38  		md.AddNext(newBits64(bit))
    39  		require.Equal(t, ^(bit<<1 - 1), md.ForkSequence().FinishSequence().FoldToUint64())
    40  	}
    41  	require.Equal(t, 128, md.Count())
    42  	require.Equal(t, uint64(0), md.FinishSequence().FoldToUint64())
    43  }
    44  
    45  func TestStackedCalculator_EntryPos(t *testing.T) {
    46  	// this table is a number of right-to-left transitions
    47  	expectedPos := [0x3b]byte{
    48  		//  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
    49  		0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
    50  		1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    51  		1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    52  		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, // overflow
    53  	}
    54  
    55  	for balanced := 0; balanced <= 1; balanced++ {
    56  		t.Run(fmt.Sprintf("balanced=%v", balanced != 0), func(t *testing.T) {
    57  			for markBit := uint64(1); markBit < uint64(1)<<uint8(len(expectedPos)); /* to avoid overflow in this test */ markBit <<= 1 {
    58  				var md ForkingCalculator
    59  				if balanced != 0 {
    60  					md = NewForkingCalculator(xorShiftPairDigester{}, cryptkit.NewDigest(newBits64(0), "uint64"))
    61  				} else {
    62  					md = NewForkingCalculator(xorShiftPairDigester{}, cryptkit.Digest{})
    63  				}
    64  
    65  				for bit := uint64(1); bit != markBit; bit <<= 1 {
    66  					md.AddNext(newBits64(0))
    67  				}
    68  				md.AddNext(newBits64(markBit))
    69  
    70  				markBitPos := bits.Len64(markBit) - 1
    71  				expected := byte(markBitPos) + expectedPos[markBitPos]
    72  
    73  				v := md.ForkSequence().FinishSequence().FoldToUint64()
    74  				require.Equal(t, 1, bits.OnesCount64(v), "0x%x", markBitPos)
    75  				require.Equal(t, expected, byte(bits.Len64(v)-1), "0x%x", markBitPos)
    76  
    77  				for bit := uint64(markBit) << 1; bit != 0; bit <<= 1 {
    78  					md.AddNext(newBits64(0))
    79  					v := md.ForkSequence().FinishSequence().FoldToUint64()
    80  					require.Equal(t, expected, byte(bits.Len64(v)-1), "0x%x", markBitPos)
    81  				}
    82  				require.Equal(t, 64, md.Count())
    83  			}
    84  		})
    85  	}
    86  }
    87  
    88  func TestStackedCalculator_Balanced_AllEntries(t *testing.T) {
    89  	const unbalanced = uint64(1 << 56)
    90  	expectedUnbalanced := [32]byte{
    91  		1, 0, 1, 0, 2, 1, 1, 0, 3, 2, 2, 1, 2, 1, 1, 0,
    92  		4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}
    93  
    94  	md := NewForkingCalculator(xorCountPairDigester{}, cryptkit.NewDigest(newBits64(unbalanced), "uint64"))
    95  
    96  	require.Equal(t, unbalanced, md.ForkSequence().FinishSequence().FoldToUint64())
    97  
    98  	for bit := uint64(1); bit <= 1<<31; bit <<= 1 {
    99  		md.AddNext(newBits64(bit))
   100  		v := md.ForkSequence().FinishSequence().FoldToUint64()
   101  
   102  		require.Equal(t, uint64(expectedUnbalanced[bits.Len64(bit)-1]), v>>56, bits.Len64(bit))
   103  		require.Equal(t, bit<<1-1, v&math.MaxUint32, bits.Len64(bit))
   104  	}
   105  	require.Equal(t, 32, md.Count())
   106  	require.Equal(t, uint64(math.MaxUint32), md.ForkSequence().FinishSequence().FoldToUint64())
   107  
   108  	md2 := md.ForkSequence()
   109  	for bit := uint64(1) << 31; bit != 0; bit >>= 1 {
   110  		md2.AddNext(newBits64(bit))
   111  		v := md2.ForkSequence().FinishSequence().FoldToUint64()
   112  		//fmt.Println(v>>56)
   113  		require.Equal(t, bit-1, v&math.MaxUint32)
   114  	}
   115  	require.Equal(t, uint64(0), md2.FinishSequence().FoldToUint64())
   116  
   117  	for bit := uint64(1); bit <= 1<<31; bit <<= 1 {
   118  		md.AddNext(newBits64(bit))
   119  		v := md.ForkSequence().FinishSequence().FoldToUint64()
   120  		//fmt.Println(v>>56)
   121  		require.Equal(t, ^uint32(bit<<1-1), uint32(v))
   122  	}
   123  	require.Equal(t, 64, md.Count())
   124  	require.Equal(t, uint64(0), md.FinishSequence().FoldToUint64())
   125  }
   126  
   127  func newBits64(v uint64) *longbits.Bits64 {
   128  	v64 := longbits.NewBits64(v)
   129  	return &v64
   130  }
   131  
   132  type xorPairDigester struct{}
   133  
   134  func (p xorPairDigester) GetDigestSize() int {
   135  	return 8
   136  }
   137  
   138  func (p xorPairDigester) DigestPair(digest0 longbits.FoldableReader, digest1 longbits.FoldableReader) cryptkit.Digest {
   139  	return cryptkit.NewDigest(newBits64(digest0.FoldToUint64()^digest1.FoldToUint64()), "uint64")
   140  }
   141  
   142  func (p xorPairDigester) GetDigestMethod() cryptkit.DigestMethod {
   143  	return "xor64"
   144  }
   145  
   146  type xorCountPairDigester struct {
   147  	xorPairDigester
   148  }
   149  
   150  func (p xorCountPairDigester) DigestPair(digest0 longbits.FoldableReader, digest1 longbits.FoldableReader) cryptkit.Digest {
   151  	const topByteMask = ^uint64(math.MaxUint64 >> 8)
   152  
   153  	v0 := digest0.FoldToUint64()
   154  	v1 := digest1.FoldToUint64()
   155  	xored := (v0 ^ v1) &^ topByteMask
   156  	//	counted := uint64(0)
   157  	counted := v0&topByteMask + v1&topByteMask
   158  	return cryptkit.NewDigest(newBits64(counted|xored), "uint64")
   159  }
   160  
   161  type xorShiftPairDigester struct {
   162  	xorPairDigester
   163  }
   164  
   165  func (p xorShiftPairDigester) DigestPair(digest0 longbits.FoldableReader, digest1 longbits.FoldableReader) cryptkit.Digest {
   166  	v0 := digest0.FoldToUint64()
   167  	v1 := digest1.FoldToUint64()
   168  	return cryptkit.NewDigest(newBits64(v0^(v1<<1)), "uint64")
   169  }