github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/routing/keyspace/xor.go (about) 1 package keyspace 2 3 import ( 4 "bytes" 5 "crypto/sha256" 6 "math/big" 7 8 u "github.com/ipfs/go-ipfs/util" 9 ) 10 11 // XORKeySpace is a KeySpace which: 12 // - normalizes identifiers using a cryptographic hash (sha256) 13 // - measures distance by XORing keys together 14 var XORKeySpace = &xorKeySpace{} 15 var _ KeySpace = XORKeySpace // ensure it conforms 16 17 type xorKeySpace struct{} 18 19 // Key converts an identifier into a Key in this space. 20 func (s *xorKeySpace) Key(id []byte) Key { 21 hash := sha256.Sum256(id) 22 key := hash[:] 23 return Key{ 24 Space: s, 25 Original: id, 26 Bytes: key, 27 } 28 } 29 30 // Equal returns whether keys are equal in this key space 31 func (s *xorKeySpace) Equal(k1, k2 Key) bool { 32 return bytes.Equal(k1.Bytes, k2.Bytes) 33 } 34 35 // Distance returns the distance metric in this key space 36 func (s *xorKeySpace) Distance(k1, k2 Key) *big.Int { 37 // XOR the keys 38 k3 := u.XOR(k1.Bytes, k2.Bytes) 39 40 // interpret it as an integer 41 dist := big.NewInt(0).SetBytes(k3) 42 return dist 43 } 44 45 // Less returns whether the first key is smaller than the second. 46 func (s *xorKeySpace) Less(k1, k2 Key) bool { 47 a := k1.Bytes 48 b := k2.Bytes 49 for i := 0; i < len(a); i++ { 50 if a[i] != b[i] { 51 return a[i] < b[i] 52 } 53 } 54 return true 55 } 56 57 // ZeroPrefixLen returns the number of consecutive zeroes in a byte slice. 58 func ZeroPrefixLen(id []byte) int { 59 for i := 0; i < len(id); i++ { 60 for j := 0; j < 8; j++ { 61 if (id[i]>>uint8(7-j))&0x1 != 0 { 62 return i*8 + j 63 } 64 } 65 } 66 return len(id) * 8 67 }