github.com/oskarth/go-ethereum@v1.6.8-0.20191013093314-dac24a9d3494/swarm/pot/address.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum 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-ethereum 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-ethereum 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/ethereum/go-ethereum/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  // ProxCmp compares the distances a->target and b->target.
    83  // Returns -1 if a is closer to target, 1 if b is closer to target
    84  // and 0 if they are equal.
    85  func ProxCmp(a, x, y interface{}) int {
    86  	return proxCmp(ToBytes(a), ToBytes(x), ToBytes(y))
    87  }
    88  
    89  func proxCmp(a, x, y []byte) int {
    90  	for i := range a {
    91  		dx := x[i] ^ a[i]
    92  		dy := y[i] ^ a[i]
    93  		if dx > dy {
    94  			return 1
    95  		} else if dx < dy {
    96  			return -1
    97  		}
    98  	}
    99  	return 0
   100  }
   101  
   102  // RandomAddressAt (address, prox) generates a random address
   103  // at proximity order prox relative to address
   104  // if prox is negative a random address is generated
   105  func RandomAddressAt(self Address, prox int) (addr Address) {
   106  	addr = self
   107  	pos := -1
   108  	if prox >= 0 {
   109  		pos = prox / 8
   110  		trans := prox % 8
   111  		transbytea := byte(0)
   112  		for j := 0; j <= trans; j++ {
   113  			transbytea |= 1 << uint8(7-j)
   114  		}
   115  		flipbyte := byte(1 << uint8(7-trans))
   116  		transbyteb := transbytea ^ byte(255)
   117  		randbyte := byte(rand.Intn(255))
   118  		addr[pos] = ((addr[pos] & transbytea) ^ flipbyte) | randbyte&transbyteb
   119  	}
   120  	for i := pos + 1; i < len(addr); i++ {
   121  		addr[i] = byte(rand.Intn(255))
   122  	}
   123  
   124  	return
   125  }
   126  
   127  // RandomAddress generates a random address
   128  func RandomAddress() Address {
   129  	return RandomAddressAt(Address{}, -1)
   130  }
   131  
   132  // NewAddressFromString creates a byte slice from a string in binary representation
   133  func NewAddressFromString(s string) []byte {
   134  	ha := [32]byte{}
   135  
   136  	t := s + zerosBin[:len(zerosBin)-len(s)]
   137  	for i := 0; i < 4; i++ {
   138  		n, err := strconv.ParseUint(t[i*64:(i+1)*64], 2, 64)
   139  		if err != nil {
   140  			panic("wrong format: " + err.Error())
   141  		}
   142  		binary.BigEndian.PutUint64(ha[i*8:(i+1)*8], n)
   143  	}
   144  	return ha[:]
   145  }
   146  
   147  // BytesAddress is an interface for elements addressable by a byte slice
   148  type BytesAddress interface {
   149  	Address() []byte
   150  }
   151  
   152  // ToBytes turns the Val into bytes
   153  func ToBytes(v Val) []byte {
   154  	if v == nil {
   155  		return nil
   156  	}
   157  	b, ok := v.([]byte)
   158  	if !ok {
   159  		ba, ok := v.(BytesAddress)
   160  		if !ok {
   161  			panic(fmt.Sprintf("unsupported value type %T", v))
   162  		}
   163  		b = ba.Address()
   164  	}
   165  	return b
   166  }
   167  
   168  // DefaultPof returns a proximity order comparison operator function
   169  // where all
   170  func DefaultPof(max int) func(one, other Val, pos int) (int, bool) {
   171  	return func(one, other Val, pos int) (int, bool) {
   172  		po, eq := proximityOrder(ToBytes(one), ToBytes(other), pos)
   173  		if po >= max {
   174  			eq = true
   175  			po = max
   176  		}
   177  		return po, eq
   178  	}
   179  }
   180  
   181  func proximityOrder(one, other []byte, pos int) (int, bool) {
   182  	for i := pos / 8; i < len(one); i++ {
   183  		if one[i] == other[i] {
   184  			continue
   185  		}
   186  		oxo := one[i] ^ other[i]
   187  		start := 0
   188  		if i == pos/8 {
   189  			start = pos % 8
   190  		}
   191  		for j := start; j < 8; j++ {
   192  			if (oxo>>uint8(7-j))&0x01 != 0 {
   193  				return i*8 + j, false
   194  			}
   195  		}
   196  	}
   197  	return len(one) * 8, true
   198  }
   199  
   200  // Label displays the node's key in binary format
   201  func Label(v Val) string {
   202  	if v == nil {
   203  		return "<nil>"
   204  	}
   205  	if s, ok := v.(fmt.Stringer); ok {
   206  		return s.String()
   207  	}
   208  	if b, ok := v.([]byte); ok {
   209  		return ToBin(b)
   210  	}
   211  	panic(fmt.Sprintf("unsupported value type %T", v))
   212  }