util.go 1.8 KB
Newer Older
1 2 3 4 5
package dht

import (
	"bytes"
	"crypto/sha256"
6
	"errors"
7 8 9 10 11

	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

12 13 14 15
// Returned if a routing table query returns no results. This is NOT expected
// behaviour
var ErrLookupFailure = errors.New("failed to find any peer in table")

16 17 18 19 20 21 22
// ID for IpfsDHT should be a byte slice, to allow for simpler operations
// (xor). DHT ids are based on the peer.IDs.
//
// The type dht.ID signifies that its contents have been hashed from either a
// peer.ID or a util.Key. This unifies the keyspace
type ID []byte

23
func (id ID) equal(other ID) bool {
24 25 26
	return bytes.Equal(id, other)
}

27
func (id ID) less(other ID) bool {
28
	a, b := equalizeSizes(id, other)
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
	for i := 0; i < len(a); i++ {
		if a[i] != b[i] {
			return a[i] < b[i]
		}
	}
	return len(a) < len(b)
}

func (id ID) commonPrefixLen() int {
	for i := 0; i < len(id); i++ {
		for j := 0; j < 8; j++ {
			if (id[i]>>uint8(7-j))&0x1 != 0 {
				return i*8 + j
			}
		}
	}
	return len(id)*8 - 1
}

func prefLen(a, b ID) int {
	return xor(a, b).commonPrefixLen()
}

func xor(a, b ID) ID {
	a, b = equalizeSizes(a, b)

	c := make(ID, len(a))
	for i := 0; i < len(a); i++ {
		c[i] = a[i] ^ b[i]
	}
	return c
}

func equalizeSizes(a, b ID) (ID, ID) {
	la := len(a)
	lb := len(b)

	if la < lb {
		na := make([]byte, lb)
		copy(na, a)
		a = na
	} else if lb < la {
		nb := make([]byte, la)
		copy(nb, b)
		b = nb
	}

	return a, b
}

79
func convertPeerID(id peer.ID) ID {
80 81 82 83
	hash := sha256.Sum256(id)
	return hash[:]
}

84
func convertKey(id u.Key) ID {
85 86 87
	hash := sha256.Sum256([]byte(id))
	return hash[:]
}
88

89
// Closer returns true if a is closer to key than b is
90
func Closer(a, b peer.ID, key u.Key) bool {
91 92 93
	aid := convertPeerID(a)
	bid := convertPeerID(b)
	tgt := convertKey(key)
94 95 96
	adist := xor(aid, tgt)
	bdist := xor(bid, tgt)

97
	return adist.less(bdist)
98
}