// Copyright 2017 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package pot import ( "encoding/binary" "fmt" "math/rand" "strconv" "strings" "github.com/ethereum/go-ethereum/common" ) var ( zeroAddr = &common.Hash{} zerosHex = zeroAddr.Hex()[2:] zerosBin = Address{}.Bin() ) var ( addrlen = keylen ) type Address common.Hash func (a Address) String() string { return fmt.Sprintf("%x", a[:]) } func (a *Address) MarshalJSON() (out []byte, err error) { return []byte(`"` + a.String() + `"`), nil } func (a *Address) UnmarshalJSON(value []byte) error { *a = Address(common.HexToHash(string(value[1 : len(value)-1]))) return nil } // the string form of the binary representation of an address (only first 8 bits) func (a Address) Bin() string { return ToBin(a[:]) } func ToBin(a []byte) string { var bs []string for _, b := range a { bs = append(bs, fmt.Sprintf("%08b", b)) } return strings.Join(bs, "") } func (a Address) Bytes() []byte { return a[:] } /* Proximity(x, y) returns the proximity order of the MSB distance between x and y The distance metric MSB(x, y) of two equal length byte sequences x an y is the value of the binary integer cast of the x^y, ie., x and y bitwise xor-ed. the binary cast is big endian: most significant bit first (=MSB). Proximity(x, y) is a discrete logarithmic scaling of the MSB distance. It is defined as the reverse rank of the integer part of the base 2 logarithm of the distance. It is calculated by counting the number of common leading zeros in the (MSB) binary representation of the x^y. (0 farthest, 255 closest, 256 self) */ func proximity(one, other Address) (ret int, eq bool) { return posProximity(one, other, 0) } // posProximity(a, b, pos) returns proximity order of b wrt a (symmetric) pretending // the first pos bits match, checking only bits kzindex >= pos func posProximity(one, other Address, pos int) (ret int, eq bool) { for i := pos / 8; i < len(one); i++ { if one[i] == other[i] { continue } oxo := one[i] ^ other[i] start := 0 if i == pos/8 { start = pos % 8 } for j := start; j < 8; j++ { if (uint8(oxo)>>uint8(7-j))&0x01 != 0 { return i*8 + j, false } } } return len(one) * 8, true } // Address.ProxCmp compares the distances a->target and b->target. // Returns -1 if a is closer to target, 1 if b is closer to target // and 0 if they are equal. func (target Address) ProxCmp(a, b Address) int { for i := range target { da := a[i] ^ target[i] db := b[i] ^ target[i] if da > db { return 1 } else if da < db { return -1 } } return 0 } // randomAddressAt(address, prox) generates a random address // at proximity order prox relative to address // if prox is negative a random address is generated func RandomAddressAt(self Address, prox int) (addr Address) { addr = self pos := -1 if prox >= 0 { pos = prox / 8 trans := prox % 8 transbytea := byte(0) for j := 0; j <= trans; j++ { transbytea |= 1 << uint8(7-j) } flipbyte := byte(1 << uint8(7-trans)) transbyteb := transbytea ^ byte(255) randbyte := byte(rand.Intn(255)) addr[pos] = ((addr[pos] & transbytea) ^ flipbyte) | randbyte&transbyteb } for i := pos + 1; i < len(addr); i++ { addr[i] = byte(rand.Intn(255)) } return } // KeyRange(a0, a1, proxLimit) returns the address inclusive address // range that contain addresses closer to one than other // func KeyRange(one, other Address, proxLimit int) (start, stop Address) { // prox := proximity(one, other) // if prox >= proxLimit { // prox = proxLimit // } // start = CommonBitsAddrByte(one, other, byte(0x00), prox) // stop = CommonBitsAddrByte(one, other, byte(0xff), prox) // return // } func CommonBitsAddrF(self, other Address, f func() byte, p int) (addr Address) { prox, _ := proximity(self, other) var pos int if p <= prox { prox = p } pos = prox / 8 addr = self trans := byte(prox % 8) var transbytea byte if p > prox { transbytea = byte(0x7f) } else { transbytea = byte(0xff) } transbytea >>= trans transbyteb := transbytea ^ byte(0xff) addrpos := addr[pos] addrpos &= transbyteb if p > prox { addrpos ^= byte(0x80 >> trans) } addrpos |= transbytea & f() addr[pos] = addrpos for i := pos + 1; i < len(addr); i++ { addr[i] = f() } return } func CommonBitsAddr(self, other Address, prox int) (addr Address) { return CommonBitsAddrF(self, other, func() byte { return byte(rand.Intn(255)) }, prox) } func CommonBitsAddrByte(self, other Address, b byte, prox int) (addr Address) { return CommonBitsAddrF(self, other, func() byte { return b }, prox) } // randomAddressAt() generates a random address func RandomAddress() Address { return RandomAddressAt(Address{}, -1) } // wraps an Address to implement the PotVal interface type HashAddress struct { Address } func (a *HashAddress) String() string { return a.Address.Bin() } func NewAddressFromString(s string) []byte { ha := [32]byte{} t := s + string(zerosBin)[:len(zerosBin)-len(s)] for i := 0; i < 4; i++ { n, err := strconv.ParseUint(t[i*64:(i+1)*64], 2, 64) if err != nil { panic("wrong format: " + err.Error()) } binary.BigEndian.PutUint64(ha[i*8:(i+1)*8], uint64(n)) } return ha[:] } func NewHashAddress(s string) *HashAddress { ha := NewAddressFromString(s) h := common.Hash{} copy(h[:], ha) return &HashAddress{Address(h)} } func NewHashAddressFromBytes(b []byte) *HashAddress { h := common.Hash{} copy(h[:], b) return &HashAddress{Address(h)} } // PO(addr, pos) return the proximity order of addr wrt to // the pinned address of the tree // assuming it is greater than or equal to pos func (self *HashAddress) PO(val PotVal, pos int) (po int, eq bool) { return posProximity(self.Address, val.(*HashAddress).Address, pos) } type BoolAddress struct { addr []bool } func NewBoolAddress(s string) *BoolAddress { return NewBoolAddressXOR(s, zerosBin[:len(s)]) } func NewBoolAddressXOR(s, t string) *BoolAddress { if len(s) != len(t) { panic("lengths do not match") } addr := make([]bool, len(s)) for i, _ := range addr { addr[i] = s[i] != t[i] } return &BoolAddress{addr} } func (self *BoolAddress) String() string { a := self.addr s := []byte(zerosBin)[:len(a)] for i, one := range a { if one { s[i] = byte('1') } } return string(s) } func (self *BoolAddress) PO(val PotVal, pos int) (po int, eq bool) { a := self.addr b := val.(*BoolAddress).addr for po = pos; po < len(b); po++ { if a[po] != b[po] { return po, false } } return po, true } type BytesAddress interface { Bytes() []byte } type bytesAddress struct { bytes []byte toBytes func(v AnyVal) []byte } func NewBytesVal(v AnyVal, f func(v AnyVal) []byte) *bytesAddress { if f == nil { f = ToBytes } b := f(v) return &bytesAddress{b, f} } func ToBytes(v AnyVal) []byte { b, ok := v.([]byte) if !ok { ba, ok := v.(BytesAddress) if !ok { panic(fmt.Sprintf("unsupported value type %T", v)) } b = ba.Bytes() } return b } func (a *bytesAddress) String() string { return fmt.Sprintf("%08b", a.bytes) } func (a *bytesAddress) Bytes() []byte { return a.bytes } func (a *bytesAddress) PO(val PotVal, i int) (int, bool) { return proximityOrder(a.bytes, a.toBytes(val), i) } func proximityOrder(one, other []byte, pos int) (int, bool) { for i := pos / 8; i < len(one); i++ { if one[i] == other[i] { continue } oxo := one[i] ^ other[i] start := 0 if i == pos/8 { start = pos % 8 } for j := start; j < 8; j++ { if (uint8(oxo)>>uint8(7-j))&0x01 != 0 { return i*8 + j, false } } } return len(one) * 8, true }