github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/merkletree2/position_test.go (about) 1 package merkletree2 2 3 import ( 4 "fmt" 5 "math/big" 6 "strconv" 7 "testing" 8 9 "github.com/stretchr/testify/require" 10 ) 11 12 func TestEncoding(t *testing.T) { 13 14 config1bit, config2bits, config3bits := getTreeCfgsWith1_2_3BitsPerIndexUnblinded(t) 15 16 encodingTests := []struct { 17 c Config 18 bin string 19 p Position 20 }{ 21 {config1bit, "1", *config1bit.GetRootPosition()}, 22 {config2bits, "1", *config2bits.GetRootPosition()}, 23 {config3bits, "1", *config3bits.GetRootPosition()}, 24 {config1bit, "10", *config1bit.GetChild(config1bit.GetRootPosition(), 0)}, 25 {config2bits, "100", *config2bits.GetChild(config2bits.GetRootPosition(), 0)}, 26 {config3bits, "1000", *config3bits.GetChild(config3bits.GetRootPosition(), 0)}, 27 {config1bit, "101", *config1bit.GetChild(config1bit.GetChild(config1bit.GetRootPosition(), 0), 1)}, 28 {config2bits, "10011", *config2bits.GetChild(config2bits.GetChild(config2bits.GetRootPosition(), 0), 3)}, 29 {config3bits, "1000101", *config3bits.GetChild(config3bits.GetChild(config3bits.GetRootPosition(), 0), 5)}, 30 } 31 32 for _, et := range encodingTests { 33 t.Run(fmt.Sprintf("%v bits: %s", et.c.BitsPerIndex, et.bin), func(t *testing.T) { 34 exp, err := strconv.ParseInt(et.bin, 2, 64) 35 require.NoError(t, err) 36 require.Equal(t, exp, (*big.Int)(&et.p).Int64()) 37 }) 38 } 39 } 40 41 func TestGetAndUpdateParentAndGetChild(t *testing.T) { 42 43 config1bit, config2bits, config3bits := getTreeCfgsWith1_2_3BitsPerIndexUnblinded(t) 44 45 parentChildTests := []struct { 46 c Config 47 parent string 48 child string 49 i ChildIndex 50 }{ 51 {config1bit, "1", "10", 0}, 52 {config1bit, "1", "11", 1}, 53 {config1bit, "11", "111", 1}, 54 {config2bits, "1", "100", 0}, 55 {config2bits, "1", "101", 1}, 56 {config2bits, "1000100", "100010011", 3}, 57 {config3bits, "1", "1100", 4}, 58 {config3bits, "1111", "1111101", 5}, 59 } 60 61 for _, test := range parentChildTests { 62 t.Run(fmt.Sprintf("%v bits: %s -(%v)-> %s", test.c.BitsPerIndex, test.parent, test.i, test.child), func(t *testing.T) { 63 child, err := makePositionFromStringForTesting(test.child) 64 require.NoError(t, err) 65 parent, err := makePositionFromStringForTesting(test.parent) 66 require.NoError(t, err) 67 require.True(t, test.c.getParent(&child).Equals(&parent)) 68 require.True(t, test.c.GetChild(&parent, test.i).Equals(&child)) 69 parentInPlace := child.Clone() 70 test.c.updateToParent(parentInPlace) 71 require.True(t, parentInPlace.Equals(&parent)) 72 }) 73 } 74 } 75 76 func TestUpdateToParentAtLevel(t *testing.T) { 77 78 config1bit, config2bits, config3bits := getTreeCfgsWith1_2_3BitsPerIndexUnblinded(t) 79 80 tests := []struct { 81 c Config 82 parent string 83 child string 84 level uint 85 }{ 86 {config1bit, "1", "1", 0}, 87 {config1bit, "1", "10", 0}, 88 {config1bit, "1", "1100100", 0}, 89 {config2bits, "1", "1100", 0}, 90 {config3bits, "1", "1111101", 0}, 91 {config1bit, "111", "111", 2}, 92 {config1bit, "110", "11010", 2}, 93 {config2bits, "110", "11001", 1}, 94 {config3bits, "1111", "1111101", 1}, 95 {config3bits, "1111001000", "1111001000001000", 3}, 96 } 97 98 for _, test := range tests { 99 t.Run(fmt.Sprintf("%v bits: %s -(%v)-> %s", test.c.BitsPerIndex, test.child, test.level, test.parent), func(t *testing.T) { 100 childToUpdate, err := makePositionFromStringForTesting(test.child) 101 require.NoError(t, err) 102 parent, err := makePositionFromStringForTesting(test.parent) 103 require.NoError(t, err) 104 test.c.updateToParentAtLevel(&childToUpdate, test.level) 105 require.True(t, parent.Equals(&childToUpdate), "expected: %x actual: %x", parent, childToUpdate) 106 }) 107 } 108 109 } 110 111 func TestUpdateToParentAndAllSiblings(t *testing.T) { 112 113 config1bit, config2bits, config3bits := getTreeCfgsWith1_2_3BitsPerIndexUnblinded(t) 114 115 tests := []struct { 116 c Config 117 pStr string 118 expParentStr string 119 expSiblings []string 120 }{ 121 {config1bit, "1001111", "100111", []string{"1001110"}}, 122 {config1bit, "1001", "100", []string{"1000"}}, 123 {config2bits, "1001111", "10011", []string{"1001100", "1001101", "1001110"}}, 124 {config3bits, "1001111", "1001", []string{"1001000", "1001001", "1001010", "1001011", "1001100", "1001101", "1001110"}}, 125 } 126 127 for _, test := range tests { 128 t.Run(fmt.Sprintf("%v bits: %v", test.c.BitsPerIndex, test.pStr), func(t *testing.T) { 129 p, err := makePositionFromStringForTesting(test.pStr) 130 require.NoError(t, err) 131 parent, err := makePositionFromStringForTesting(test.expParentStr) 132 require.NoError(t, err) 133 siblings := make([]Position, test.c.ChildrenPerNode-1) 134 135 test.c.updateToParentAndAllSiblings(&p, siblings) 136 require.True(t, p.Equals(&parent)) 137 for i, expPosStr := range test.expSiblings { 138 expPos, err := makePositionFromStringForTesting(expPosStr) 139 require.NoError(t, err) 140 require.True(t, expPos.Equals(&siblings[i]), "Error at sibling %v, got %v", expPosStr, siblings[i]) 141 } 142 }) 143 } 144 } 145 146 func TestNewConfigError(t *testing.T) { 147 148 _, err := NewConfig(nil, false, 5, 8, 6, ConstructStringValueContainer) 149 require.Error(t, err) 150 require.IsType(t, InvalidConfigError{}, err) 151 152 c, err := NewConfig(nil, false, 2, 4, 32, ConstructStringValueContainer) 153 require.NoError(t, err) 154 155 require.Equal(t, 1<<c.BitsPerIndex, c.ChildrenPerNode) 156 } 157 158 func TestPositionIsOnPathToKey(t *testing.T) { 159 160 config1bit, config2bits, config3bits := getTreeCfgsWith1_2_3BitsPerIndexUnblinded(t) 161 162 tests := []struct { 163 c Config 164 p string 165 k Key 166 expected bool 167 }{ 168 {config1bit, "1", []byte{0x00, 0x01, 0x02}, true}, 169 {config2bits, "1", []byte{0x00, 0x01, 0x02}, true}, 170 {config3bits, "1", []byte{0x00, 0x01, 0x02}, true}, 171 {config1bit, "10", []byte{0x00, 0x01, 0x02}, true}, 172 {config2bits, "100", []byte{0x00, 0x01, 0x02}, true}, 173 {config3bits, "1000", []byte{0x00, 0x01, 0x02}, true}, 174 {config1bit, "11", []byte{0x00, 0x01, 0x02}, false}, 175 {config2bits, "110", []byte{0x00, 0x01, 0x02}, false}, 176 {config3bits, "1100", []byte{0x00, 0x01, 0x02}, false}, 177 {config1bit, "101", []byte{0x00, 0x01, 0x02}, false}, 178 {config2bits, "1000000000000000100", []byte{0x00, 0x01, 0x02}, true}, 179 {config2bits, "1000000000000000000", []byte{0x00, 0x01, 0x02}, false}, 180 } 181 182 for _, test := range tests { 183 t.Run(fmt.Sprintf("%v bits: %v %v", test.c.BitsPerIndex, test.p, test.k), func(t *testing.T) { 184 pos, err := makePositionFromStringForTesting(test.p) 185 require.NoError(t, err) 186 require.Equal(t, test.expected, pos.isOnPathToKey(test.k)) 187 }) 188 } 189 190 } 191 192 func TestGetDeepestPositionAtLevelAndSiblingsOnPathToKey(t *testing.T) { 193 194 config1bit, config2bits, _ := getTreeCfgsWith1_2_3BitsPerIndexUnblinded(t) 195 196 tests := []struct { 197 c Config 198 lastLevel int 199 firstLevel int 200 k Key 201 expPosOnPath []string 202 }{ 203 {config1bit, 8, 1, []byte{0xf0}, []string{"111110000", "111110001", "11111001", "1111101", "111111", "11110", "1110", "110", "10"}}, 204 {config1bit, 2, 1, []byte{0xf0}, []string{"111", "110", "10"}}, 205 {config1bit, 3, 1, []byte{0xf0}, []string{"1111", "1110", "110", "10"}}, 206 {config1bit, 3, 2, []byte{0xf0}, []string{"1111", "1110", "110"}}, 207 {config1bit, 4, 2, []byte{0xf0}, []string{"11111", "11110", "1110", "110"}}, 208 {config1bit, 8, 1, []byte{0x00}, []string{"100000000", "100000001", "10000001", "1000001", "100001", "10001", "1001", "101", "11"}}, 209 {config1bit, 2, 1, []byte{0x00}, []string{"100", "101", "11"}}, 210 {config1bit, 3, 1, []byte{0x00}, []string{"1000", "1001", "101", "11"}}, 211 {config1bit, 3, 2, []byte{0x00}, []string{"1000", "1001", "101"}}, 212 {config1bit, 4, 2, []byte{0x00}, []string{"10000", "10001", "1001", "101"}}, 213 {config1bit, 1, 1, []byte{0x00}, []string{"10", "11"}}, 214 {config2bits, 4, 1, []byte{0xf1}, []string{"111110001", "111110000", "111110010", "111110011", "1111101", "1111110", "1111111", "11100", "11101", "11110", "100", "101", "110"}}, 215 } 216 217 for _, test := range tests { 218 t.Run(fmt.Sprintf("%v bits: %v", test.c.BitsPerIndex, test.k), func(t *testing.T) { 219 posOnPath := test.c.getDeepestPositionAtLevelAndSiblingsOnPathToKey(test.k, test.lastLevel, test.firstLevel) 220 require.Equal(t, len(test.expPosOnPath), len(posOnPath)) 221 for i, expPosStr := range test.expPosOnPath { 222 expPos, err := makePositionFromStringForTesting(expPosStr) 223 require.NoError(t, err) 224 require.True(t, expPos.Equals(&posOnPath[i]), "Error at position %v, got %v", expPosStr, posOnPath[i]) 225 } 226 }) 227 } 228 } 229 230 func TestGetLevel(t *testing.T) { 231 232 config1bit, config2bits, config3bits := getTreeCfgsWith1_2_3BitsPerIndexUnblinded(t) 233 234 tests := []struct { 235 c Config 236 pos string 237 lev uint 238 }{ 239 {config1bit, "1", 0}, 240 {config2bits, "1", 0}, 241 {config3bits, "1", 0}, 242 {config1bit, "10", 1}, 243 {config2bits, "100", 1}, 244 {config3bits, "1001", 1}, 245 {config1bit, "1001000", 6}, 246 {config2bits, "1001000", 3}, 247 {config3bits, "1001000", 2}, 248 {config3bits, "1001000001000", 4}, 249 } 250 251 for _, test := range tests { 252 t.Run(fmt.Sprintf("%v bits: pos %v lev %v", test.c.BitsPerIndex, test.pos, test.lev), func(t *testing.T) { 253 pos, err := makePositionFromStringForTesting(test.pos) 254 require.NoError(t, err) 255 256 require.Equal(t, int(test.lev), test.c.getLevel(&pos)) 257 }) 258 } 259 260 } 261 262 func TestGetParentAtLevel(t *testing.T) { 263 264 config1bit, config2bits, config3bits := getTreeCfgsWith1_2_3BitsPerIndexUnblinded(t) 265 266 tests := []struct { 267 c Config 268 pos string 269 par string 270 lev uint 271 }{ 272 {config1bit, "1001000", "1", 0}, 273 {config2bits, "1001000", "1", 0}, 274 {config3bits, "1001000", "1", 0}, 275 {config1bit, "1001000", "10", 1}, 276 {config2bits, "1001000", "100", 1}, 277 {config3bits, "1001000", "1001", 1}, 278 {config1bit, "1001000", "100", 2}, 279 {config2bits, "1001000", "10010", 2}, 280 {config3bits, "1001000", "1001000", 2}, 281 {config3bits, "1001000001000", "1001000", 2}, 282 } 283 284 for _, test := range tests { 285 t.Run(fmt.Sprintf("%v bits: pos %v lev %v", test.c.BitsPerIndex, test.pos, test.lev), func(t *testing.T) { 286 pos, err := makePositionFromStringForTesting(test.pos) 287 require.NoError(t, err) 288 expParent, err := makePositionFromStringForTesting(test.par) 289 require.NoError(t, err) 290 291 require.True(t, expParent.Equals(test.c.getParentAtLevel(&pos, test.lev))) 292 }) 293 } 294 295 } 296 297 func TestPositionToChildIndexPath(t *testing.T) { 298 299 config1bit, config2bits, config3bits := getTreeCfgsWith1_2_3BitsPerIndexUnblinded(t) 300 301 tests := []struct { 302 c Config 303 pos string 304 p []ChildIndex 305 }{ 306 {config1bit, "1", []ChildIndex{}}, 307 {config2bits, "1", []ChildIndex{}}, 308 {config3bits, "1", []ChildIndex{}}, 309 {config1bit, "10", []ChildIndex{0}}, 310 {config1bit, "11", []ChildIndex{1}}, 311 {config2bits, "100", []ChildIndex{0}}, 312 {config2bits, "111", []ChildIndex{3}}, 313 {config3bits, "1001", []ChildIndex{1}}, 314 {config1bit, "1001000", []ChildIndex{0, 0, 0, 1, 0, 0}}, 315 {config2bits, "1001001", []ChildIndex{1, 2, 0}}, 316 {config2bits, "1001010", []ChildIndex{2, 2, 0}}, 317 {config3bits, "1001000", []ChildIndex{0, 1}}, 318 {config3bits, "1001000001000", []ChildIndex{0, 1, 0, 1}}, 319 } 320 321 for _, test := range tests { 322 t.Run(fmt.Sprintf("%v bits: pos %v", test.c.BitsPerIndex, test.pos), func(t *testing.T) { 323 pos, err := makePositionFromStringForTesting(test.pos) 324 require.NoError(t, err) 325 326 require.Equal(t, test.p, test.c.positionToChildIndexPath(&pos)) 327 }) 328 } 329 330 } 331 332 func TestGetDeepestChildIndex(t *testing.T) { 333 334 config1bit, config2bits, config3bits := getTreeCfgsWith1_2_3BitsPerIndexUnblinded(t) 335 336 tests := []struct { 337 c Config 338 pos string 339 lev ChildIndex 340 }{ 341 {config1bit, "1", 0}, 342 {config2bits, "1", 0}, 343 {config3bits, "1", 0}, 344 {config1bit, "10", 0}, 345 {config1bit, "11", 1}, 346 {config2bits, "100", 0}, 347 {config2bits, "111", 3}, 348 {config3bits, "1001", 1}, 349 {config1bit, "1001000", 0}, 350 {config2bits, "1001001", 1}, 351 {config2bits, "1001010", 2}, 352 {config3bits, "1001000", 0}, 353 {config3bits, "1001000001110", 6}, 354 } 355 356 for _, test := range tests { 357 t.Run(fmt.Sprintf("%v bits: pos %v lev %v", test.c.BitsPerIndex, test.pos, test.lev), func(t *testing.T) { 358 pos, err := makePositionFromStringForTesting(test.pos) 359 require.NoError(t, err) 360 361 require.Equal(t, test.lev, test.c.getDeepestChildIndex(&pos)) 362 }) 363 } 364 365 } 366 367 func TestGetKeyIntervalUnderPosition(t *testing.T) { 368 369 config1bit, config2bits, config3bits := getTreeCfgsWith1_2_3BitsPerIndexUnblinded(t) 370 371 tests := []struct { 372 c Config 373 position string 374 minKey Key 375 maxKey Key 376 }{ 377 {config1bit, "1", Key([]byte{0x00}), Key([]byte{0xff})}, 378 {config1bit, "11", Key([]byte{0x80}), Key([]byte{0xff})}, 379 {config1bit, "101", Key([]byte{0x40}), Key([]byte{0x7f})}, 380 {config1bit, "10100", Key([]byte{0x40}), Key([]byte{0x4f})}, 381 {config2bits, "1", Key([]byte{0x00}), Key([]byte{0xff})}, 382 {config2bits, "101", Key([]byte{0x40}), Key([]byte{0x7f})}, 383 {config2bits, "10100", Key([]byte{0x40}), Key([]byte{0x4f})}, 384 {config3bits, "1", Key([]byte{0x00, 0x00, 0x00}), Key([]byte{0xff, 0xff, 0xff})}, 385 {config3bits, "1010", Key([]byte{0x40, 0x00, 0x00}), Key([]byte{0x5f, 0xff, 0xff})}, 386 } 387 388 for _, test := range tests { 389 t.Run(fmt.Sprintf("%v bits: %s", test.c.BitsPerIndex, test.position), func(t *testing.T) { 390 p, err := makePositionFromStringForTesting(test.position) 391 require.NoError(t, err) 392 min, max := test.c.GetKeyIntervalUnderPosition(&p) 393 require.Equal(t, test.minKey, min) 394 require.Equal(t, test.maxKey, max) 395 }) 396 } 397 398 }