github.com/aaa256/atlantis@v0.0.0-20210707112435-42ee889287a2/swarm/pot/address.go (about) 1 // Copyright 2017 The go-athereum Authors 2 // This file is part of the go-athereum library. 3 // 4 // The go-athereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-athereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-athereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package pot see doc.go 18 package pot 19 20 import ( 21 "encoding/binary" 22 "fmt" 23 "math/rand" 24 "strconv" 25 "strings" 26 27 "github.com/athereum/go-athereum/common" 28 ) 29 30 var ( 31 zerosBin = Address{}.Bin() 32 ) 33 34 // Address is an alias for common.Hash 35 type Address common.Hash 36 37 // NewAddressFromBytes constructs an Address from a byte slice 38 func NewAddressFromBytes(b []byte) Address { 39 h := common.Hash{} 40 copy(h[:], b) 41 return Address(h) 42 } 43 44 func (a Address) IsZero() bool { 45 return a.Bin() == zerosBin 46 } 47 48 func (a Address) String() string { 49 return fmt.Sprintf("%x", a[:]) 50 } 51 52 // MarshalJSON Address serialisation 53 func (a *Address) MarshalJSON() (out []byte, err error) { 54 return []byte(`"` + a.String() + `"`), nil 55 } 56 57 // UnmarshalJSON Address deserialisation 58 func (a *Address) UnmarshalJSON(value []byte) error { 59 *a = Address(common.HexToHash(string(value[1 : len(value)-1]))) 60 return nil 61 } 62 63 // Bin returns the string form of the binary representation of an address (only first 8 bits) 64 func (a Address) Bin() string { 65 return ToBin(a[:]) 66 } 67 68 // ToBin converts a byteslice to the string binary representation 69 func ToBin(a []byte) string { 70 var bs []string 71 for _, b := range a { 72 bs = append(bs, fmt.Sprintf("%08b", b)) 73 } 74 return strings.Join(bs, "") 75 } 76 77 // Bytes returns the Address as a byte slice 78 func (a Address) Bytes() []byte { 79 return a[:] 80 } 81 82 /* 83 Proximity(x, y) returns the proximity order of the MSB distance between x and y 84 85 The distance metric MSB(x, y) of two equal length byte sequences x an y is the 86 value of the binary integer cast of the x^y, ie., x and y bitwise xor-ed. 87 the binary cast is big endian: most significant bit first (=MSB). 88 89 Proximity(x, y) is a discrete logarithmic scaling of the MSB distance. 90 It is defined as the reverse rank of the integer part of the base 2 91 logarithm of the distance. 92 It is calculated by counting the number of common leading zeros in the (MSB) 93 binary representation of the x^y. 94 95 (0 farthest, 255 closest, 256 self) 96 */ 97 func proximity(one, other Address) (ret int, eq bool) { 98 return posProximity(one, other, 0) 99 } 100 101 // posProximity(a, b, pos) returns proximity order of b wrt a (symmetric) pretending 102 // the first pos bits match, checking only bits index >= pos 103 func posProximity(one, other Address, pos int) (ret int, eq bool) { 104 for i := pos / 8; i < len(one); i++ { 105 if one[i] == other[i] { 106 continue 107 } 108 oxo := one[i] ^ other[i] 109 start := 0 110 if i == pos/8 { 111 start = pos % 8 112 } 113 for j := start; j < 8; j++ { 114 if (oxo>>uint8(7-j))&0x01 != 0 { 115 return i*8 + j, false 116 } 117 } 118 } 119 return len(one) * 8, true 120 } 121 122 // ProxCmp compares the distances a->target and b->target. 123 // Returns -1 if a is closer to target, 1 if b is closer to target 124 // and 0 if they are equal. 125 func ProxCmp(a, x, y interface{}) int { 126 return proxCmp(ToBytes(a), ToBytes(x), ToBytes(y)) 127 } 128 129 func proxCmp(a, x, y []byte) int { 130 for i := range a { 131 dx := x[i] ^ a[i] 132 dy := y[i] ^ a[i] 133 if dx > dy { 134 return 1 135 } else if dx < dy { 136 return -1 137 } 138 } 139 return 0 140 } 141 142 // RandomAddressAt (address, prox) generates a random address 143 // at proximity order prox relative to address 144 // if prox is negative a random address is generated 145 func RandomAddressAt(self Address, prox int) (addr Address) { 146 addr = self 147 pos := -1 148 if prox >= 0 { 149 pos = prox / 8 150 trans := prox % 8 151 transbytea := byte(0) 152 for j := 0; j <= trans; j++ { 153 transbytea |= 1 << uint8(7-j) 154 } 155 flipbyte := byte(1 << uint8(7-trans)) 156 transbyteb := transbytea ^ byte(255) 157 randbyte := byte(rand.Intn(255)) 158 addr[pos] = ((addr[pos] & transbytea) ^ flipbyte) | randbyte&transbyteb 159 } 160 for i := pos + 1; i < len(addr); i++ { 161 addr[i] = byte(rand.Intn(255)) 162 } 163 164 return 165 } 166 167 // RandomAddress generates a random address 168 func RandomAddress() Address { 169 return RandomAddressAt(Address{}, -1) 170 } 171 172 // NewAddressFromString creates a byte slice from a string in binary representation 173 func NewAddressFromString(s string) []byte { 174 ha := [32]byte{} 175 176 t := s + zerosBin[:len(zerosBin)-len(s)] 177 for i := 0; i < 4; i++ { 178 n, err := strconv.ParseUint(t[i*64:(i+1)*64], 2, 64) 179 if err != nil { 180 panic("wrong format: " + err.Error()) 181 } 182 binary.BigEndian.PutUint64(ha[i*8:(i+1)*8], n) 183 } 184 return ha[:] 185 } 186 187 // BytesAddress is an interface for elements addressable by a byte slice 188 type BytesAddress interface { 189 Address() []byte 190 } 191 192 // ToBytes turns the Val into bytes 193 func ToBytes(v Val) []byte { 194 if v == nil { 195 return nil 196 } 197 b, ok := v.([]byte) 198 if !ok { 199 ba, ok := v.(BytesAddress) 200 if !ok { 201 panic(fmt.Sprintf("unsupported value type %T", v)) 202 } 203 b = ba.Address() 204 } 205 return b 206 } 207 208 // DefaultPof returns a proximity order comparison operator function 209 // where all 210 func DefaultPof(max int) func(one, other Val, pos int) (int, bool) { 211 return func(one, other Val, pos int) (int, bool) { 212 po, eq := proximityOrder(ToBytes(one), ToBytes(other), pos) 213 if po >= max { 214 eq = true 215 po = max 216 } 217 return po, eq 218 } 219 } 220 221 func proximityOrder(one, other []byte, pos int) (int, bool) { 222 for i := pos / 8; i < len(one); i++ { 223 if one[i] == other[i] { 224 continue 225 } 226 oxo := one[i] ^ other[i] 227 start := 0 228 if i == pos/8 { 229 start = pos % 8 230 } 231 for j := start; j < 8; j++ { 232 if (oxo>>uint8(7-j))&0x01 != 0 { 233 return i*8 + j, false 234 } 235 } 236 } 237 return len(one) * 8, true 238 } 239 240 // Label displays the node's key in binary format 241 func Label(v Val) string { 242 if v == nil { 243 return "<nil>" 244 } 245 if s, ok := v.(fmt.Stringer); ok { 246 return s.String() 247 } 248 if b, ok := v.([]byte); ok { 249 return ToBin(b) 250 } 251 panic(fmt.Sprintf("unsupported value type %T", v)) 252 }