112 lines
2.7 KiB
Java
112 lines
2.7 KiB
Java
package node;
|
|
|
|
import java.math.BigInteger;
|
|
import java.util.BitSet;
|
|
import java.util.Random;
|
|
|
|
/**
|
|
* A Kademlia identifier. Can be used for identifying files as well as nodes
|
|
* (but for nodes check {@see NodeIdentifier}).
|
|
*
|
|
* @author jln
|
|
*
|
|
*/
|
|
public class Identifier {
|
|
private static Random random = new Random(System.currentTimeMillis());
|
|
|
|
protected BitSet bits;
|
|
|
|
private int size;
|
|
|
|
public Identifier(int size, byte[] bytes) {
|
|
this.size = size;
|
|
this.bits = BitSet.valueOf(bytes);
|
|
}
|
|
|
|
private Identifier(int size, BitSet bits) {
|
|
this.size = size;
|
|
this.bits = bits;
|
|
}
|
|
|
|
/**
|
|
* Creates an ID exactly "in the middle" of the ID space. (If the ID space
|
|
* is 8 bit wide, this returns an ID valued 128).
|
|
*
|
|
* @param size
|
|
* the size of the id space
|
|
* @return an Identifier
|
|
*/
|
|
public static Identifier getStaticIdentifier(int size) {
|
|
BitSet middle = new BitSet(size);
|
|
middle.set(size - 1);
|
|
return new Identifier(size, middle);
|
|
}
|
|
|
|
/**
|
|
* Creates a random ID for the given id space size.
|
|
*
|
|
* @param size
|
|
* the size of the id space
|
|
* @return a random Identifier
|
|
*/
|
|
public static Identifier getRandomIdentifier(int size) {
|
|
BitSet bits = new BitSet(size);
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
double threshold = random.nextGaussian();
|
|
if (threshold > 0) {
|
|
bits.set(i);
|
|
}
|
|
}
|
|
|
|
return new Identifier(size, bits);
|
|
}
|
|
|
|
public BigInteger distanceTo(Identifier otherID) {
|
|
BitSet distance = (BitSet) bits.clone();
|
|
distance.xor(otherID.bits);
|
|
return new BigInteger(1, distance.toByteArray());
|
|
}
|
|
|
|
/**
|
|
* Returns whether the bit at the given position is set or not. The MSB is
|
|
* at position 0.
|
|
*
|
|
* @param index
|
|
* the index to check
|
|
* @return true if the bit is set
|
|
*/
|
|
public boolean isBitSetAt(int index) {
|
|
BigInteger intValue = new BigInteger(1, bits.toByteArray());
|
|
int numOfTrimmedZeros = size - intValue.bitLength();
|
|
|
|
if (index < numOfTrimmedZeros) {
|
|
return false;
|
|
}
|
|
|
|
return bits.get(bits.length() - (index + numOfTrimmedZeros) - 1);
|
|
}
|
|
|
|
public byte[] getBytes() {
|
|
return bits.toByteArray();
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object o) {
|
|
if (!(o instanceof Identifier)) {
|
|
return false;
|
|
} else {
|
|
return bits.equals(((Identifier) o).bits);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return toString().hashCode();
|
|
}
|
|
|
|
public String toString() {
|
|
return new BigInteger(1, bits.toByteArray()).toString();
|
|
}
|
|
}
|