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 }