github.com/ethersphere/bee/v2@v2.2.0/pkg/topology/kademlia/binprefix.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package kademlia 6 7 import ( 8 "math" 9 "math/bits" 10 11 "github.com/ethersphere/bee/v2/pkg/swarm" 12 ) 13 14 // generateCommonBinPrefixes generates the common bin prefixes 15 // used by the bin balancer. 16 func generateCommonBinPrefixes(base swarm.Address, suffixLength int) [][]swarm.Address { 17 bitCombinationsCount := int(math.Pow(2, float64(suffixLength))) 18 bitSuffixes := make([]uint8, bitCombinationsCount) 19 20 for i := 0; i < bitCombinationsCount; i++ { 21 bitSuffixes[i] = uint8(i) 22 } 23 24 binPrefixes := make([][]swarm.Address, int(swarm.MaxBins)) 25 26 // copy base address 27 for i := range binPrefixes { 28 binPrefixes[i] = make([]swarm.Address, bitCombinationsCount) 29 for j := range binPrefixes[i] { 30 binPrefixes[i][j] = base.Clone() 31 } 32 } 33 34 for i := range binPrefixes { 35 for j := range binPrefixes[i] { 36 pseudoAddrBytes := binPrefixes[i][j].Bytes() 37 38 if len(pseudoAddrBytes) < 1 { 39 continue 40 } 41 42 // flip first bit for bin 43 indexByte, posBit := i/8, i%8 44 if hasBit(bits.Reverse8(pseudoAddrBytes[indexByte]), uint8(posBit)) { 45 pseudoAddrBytes[indexByte] = bits.Reverse8(clearBit(bits.Reverse8(pseudoAddrBytes[indexByte]), uint8(posBit))) 46 } else { 47 pseudoAddrBytes[indexByte] = bits.Reverse8(setBit(bits.Reverse8(pseudoAddrBytes[indexByte]), uint8(posBit))) 48 } 49 50 // set pseudo suffix 51 bitSuffixPos := suffixLength - 1 52 for l := i + 1; l < i+suffixLength+1; l++ { 53 index, pos := l/8, l%8 54 55 if hasBit(bitSuffixes[j], uint8(bitSuffixPos)) { 56 pseudoAddrBytes[index] = bits.Reverse8(setBit(bits.Reverse8(pseudoAddrBytes[index]), uint8(pos))) 57 } else { 58 pseudoAddrBytes[index] = bits.Reverse8(clearBit(bits.Reverse8(pseudoAddrBytes[index]), uint8(pos))) 59 } 60 61 bitSuffixPos-- 62 } 63 64 // clear rest of the bits 65 for l := i + suffixLength + 1; l < len(pseudoAddrBytes)*8; l++ { 66 index, pos := l/8, l%8 67 pseudoAddrBytes[index] = bits.Reverse8(clearBit(bits.Reverse8(pseudoAddrBytes[index]), uint8(pos))) 68 } 69 } 70 } 71 72 return binPrefixes 73 } 74 75 // Clears the bit at pos in n. 76 func clearBit(n, pos uint8) uint8 { 77 mask := ^(uint8(1) << pos) 78 return n & mask 79 } 80 81 // Sets the bit at pos in the integer n. 82 func setBit(n, pos uint8) uint8 { 83 return n | 1<<pos 84 } 85 86 func hasBit(n, pos uint8) bool { 87 return n&(1<<pos) > 0 88 }