github.com/koko1123/flow-go-1@v0.29.6/storage/merkle/node_test.go (about) 1 package merkle 2 3 import ( 4 "encoding/hex" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 9 "github.com/stretchr/testify/assert" 10 "golang.org/x/crypto/blake2b" 11 ) 12 13 var payload1, _ = hex.DecodeString("62b0326507ebce9d4a242908d20559ceca965c5e9848646bd0c05047c8487aadfcb3d851e77e5a055d306e48c376f8") 14 var payload2, _ = hex.DecodeString("bab02e6213dfad3546aa473922bba0") 15 16 // TestHashTags tests the hashing tags of the node types 17 // satisfy the required conditions for the tree security properties. 18 func TestHashTags(t *testing.T) { 19 // Test tag lengths are equal 20 // This is required because the tags are prepended to the hashed value. 21 assert.Equal(t, len(leafNodeTag), len(shortNodeTag)) 22 assert.Equal(t, len(leafNodeTag), len(fullNodeTag)) 23 24 // Test tag values are not equal 25 // This is required to make sure the 3 node hash functions are orthogonal. 26 assert.NotEqual(t, leafNodeTag, shortNodeTag) 27 assert.NotEqual(t, leafNodeTag, fullNodeTag) 28 assert.NotEqual(t, shortNodeTag, fullNodeTag) 29 } 30 31 // TestBlakeMAC verifies that constructor blake2b.New256(m) never errors for any of the used MAC 32 // values `m`. This is assumed by the Node's Hash() implementations. We test this assumption holds 33 // at build time, but avoid runtime-checks for performance reasons. 34 // Context: The blake2b MAC key should be less than 64 bytes. Constructor blake2b.New256(m) checks 35 // this condition and errors, but we ignore its error return at runtime. 36 func TestBlakeMAC(t *testing.T) { 37 var e error 38 39 // leaf nodes 40 assert.True(t, len(leafNodeTag) < 64) 41 _, e = blake2b.New256(leafNodeTag[:]) 42 assert.NoError(t, e) 43 44 // full nodes 45 assert.True(t, len(fullNodeTag) < 64) 46 _, e = blake2b.New256(fullNodeTag[:]) 47 assert.NoError(t, e) 48 49 // short nodes 50 assert.True(t, len(shortNodeTag) < 64) 51 _, e = blake2b.New256(shortNodeTag[:]) 52 assert.NoError(t, e) 53 54 } 55 56 // TestLeafHash verifies that the hash of a leaf returns the expected value. 57 // We compare with a python-reference implementation 58 func TestLeafHash(t *testing.T) { 59 // reference value (from python reference implementation) 60 ref := "1b30482d4dc8c1a8d846d05765c03a33f0267b56b9a7be8defe38958f89c95fc" 61 62 l := leaf{val: payload1} 63 require.Equal(t, ref, hex.EncodeToString(l.Hash(false))) 64 // this first time doens't have cached value 65 require.Nil(t, l.cachedHashValue) 66 require.Equal(t, ref, hex.EncodeToString(l.Hash(true))) 67 // second time returns the cached value 68 require.NotNil(t, l.cachedHashValue) 69 require.Equal(t, ref, hex.EncodeToString(l.Hash(true))) 70 } 71 72 // TestShortHash verifies that the hash of a short node returns the expected value. 73 // We compare with a python-reference implementation. 74 func TestShortHash(t *testing.T) { 75 t.Run("13-bit path", func(t *testing.T) { 76 // expected value from python reference implementation 77 ref := "a5632447428968cca925e802e5251c2c2b31e4ebf5236a3a66a60fe0509d6e40" 78 79 // path of 13 bits: 1011001010011 80 // per convention, we pad zeros to the end to obtain full bytes: 81 // -> 10110010 10011000 (padded binary representation) 82 // -> 178 152 (uint8 representation) 83 // 84 path := []byte{178, 152} 85 s := short{ 86 path: path, 87 count: 13, 88 child: &leaf{val: payload1}, 89 } 90 require.Equal(t, ref, hex.EncodeToString(s.Hash(false))) 91 // this first time doens't have cached value 92 require.Equal(t, ref, hex.EncodeToString(s.Hash(true))) 93 // second time returns the cached value 94 require.Equal(t, ref, hex.EncodeToString(s.Hash(true))) 95 }) 96 97 t.Run("maxKeyLenBits-bit path", func(t *testing.T) { 98 // as path, we just repeat the following 32 bytes 256 times 99 k, _ := hex.DecodeString("1b30482d4dc8c1a8d846d05765c03a33f0267b56b9a7be8defe38958f89c95fc") 100 path := make([]byte, 0, maxKeyLength) 101 for i := 1; i <= maxKeyLength/len(k); i++ { 102 path = append(path, k...) 103 } 104 path = append(path, k[:maxKeyLength%len(k)]...) 105 // expected value from python reference implementation 106 ref := "e60e2abb4d45b01c2ccc3ea1c82d424478192fc37b31ca7ec84331b4d0f31846" 107 108 s := short{ 109 path: path, 110 count: maxKeyLenBits, 111 child: &leaf{val: payload1}, 112 } 113 require.Equal(t, ref, hex.EncodeToString(s.Hash(false))) 114 // this first time doens't have cached value 115 require.Equal(t, ref, hex.EncodeToString(s.Hash(true))) 116 // second time returns the cached value 117 require.Equal(t, ref, hex.EncodeToString(s.Hash(true))) 118 }) 119 } 120 121 // Test_ShortNodePathLengthEncoding: 122 // The tree enforces a max key length of `maxKeyLength`. We verify that: 123 // 1. the resulting number of bits (i.e. maxKeyLength * 8), does not 124 // overflow the hardware-dependent int range. 125 // 2. the value range from [1, ..., maxKeyLength * 8] can be encoded into 2 bytes, 126 // as this is required by the short node (but not enforced at run time) 127 // 3. serializedPathSegmentLength(l) 128 func Test_ShortNodePathLengthEncoding(t *testing.T) { 129 // testing 1: 130 maxInt := int(^uint(0) >> 1) // largest int value (hardware-dependent) 131 require.True(t, maxKeyLength <= maxInt/8) 132 133 // testing 2: 134 // two bytes can encode up to 2^16-1 = 65535 135 require.GreaterOrEqual(t, uint64(65535), uint64(maxKeyLength)*8) 136 137 // testing 3: 138 require.Equal(t, [2]byte{0, 1}, serializedPathSegmentLength(1)) 139 require.Equal(t, [2]byte{255, 255}, serializedPathSegmentLength(65535)) 140 } 141 142 // TestFullHash verifies that the hash of a full node returns the expected value. 143 // We compare with a python-reference implementation. 144 func TestFullHash(t *testing.T) { 145 // reference value (from python reference implementation) 146 ref := "6edee16badebe695a2ff7df90e429ba66e8986f7c9d089e4ad8fccbd89b0ccc8" 147 148 f := full{ 149 left: &leaf{val: payload1}, 150 right: &leaf{val: payload2}, 151 } 152 require.Equal(t, ref, hex.EncodeToString(f.Hash(false))) 153 // this first time doens't have cached value 154 require.Equal(t, ref, hex.EncodeToString(f.Hash(true))) 155 // second time returns the cached value 156 require.Equal(t, ref, hex.EncodeToString(f.Hash(true))) 157 } 158 159 // TestMaxDepthOfDescendants validates the functionality of the max depth of the decendencts 160 func TestMaxDepthOfDescendants(t *testing.T) { 161 //// consturcted trie 162 // full 163 // / \ 164 // short leaf 165 // | 166 // full 167 // / \ 168 // leaf short 169 // | 170 // leaf 171 //// 172 173 f := full{ 174 left: &short{ 175 child: &full{ 176 left: &leaf{}, 177 right: &short{ 178 child: &leaf{}, 179 }, 180 }, 181 }, 182 right: &leaf{}, 183 } 184 185 require.Equal(t, f.MaxDepthOfDescendants(), uint(4)) 186 }