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  }