/*
* This file is part of mlDHT.
*
* mlDHT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* mlDHT 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with mlDHT. If not, see <http://www.gnu.org/licenses/>.
*/
package lbms.plugins.mldht.kad;
import static java.lang.Math.log1p;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import lbms.plugins.mldht.kad.utils.BitVector;
public class BloomFilterBEP33 implements Comparable<BloomFilterBEP33>, Cloneable {
public final static int m = 256 * 8;
private final static int k = 2;
MessageDigest sha1;
BitVector filter;
public BloomFilterBEP33() {
filter = new BitVector(m);
try
{
sha1 = MessageDigest.getInstance("SHA1");
} catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
}
public BloomFilterBEP33(byte[] serializedFilter) {
filter = new BitVector(m,serializedFilter);
}
public void insert(InetAddress addr) {
byte[] hash = sha1.digest(addr.getAddress());
int index1 = (hash[0]&0xFF) | (hash[1]&0xFF) << 8;
int index2 = (hash[2]&0xFF) | (hash[3]&0xFF) << 8;
// truncate index to m (11 bits required)
index1 %= m;
index2 %= m;
// set bits at index1 and index2
filter.set(index1);
filter.set(index2);
}
@Override
protected BloomFilterBEP33 clone() {
BloomFilterBEP33 newFilter = null;
try
{
newFilter = (BloomFilterBEP33) super.clone();
} catch (CloneNotSupportedException e)
{
throw new Error("never happens");
}
newFilter.filter = new BitVector(filter);
return newFilter;
}
public int compareTo(BloomFilterBEP33 o) {
return size()-o.size();
}
public int size() {
// number of expected 0 bits = m * (1 − 1/m)^(k*size)
double c = filter.bitcount();
double size = log1p(-c/m) / (k * logB());
return (int) size;
}
public static int unionSize(Collection<BloomFilterBEP33> filters)
{
BitVector[] vectors = new BitVector[filters.size()];
int i = 0;
for(BloomFilterBEP33 f : filters)
vectors[i++] = f.filter;
double c = BitVector.unionAndCount(vectors);
return (int) (log1p(-c/m) / (k * logB()));
}
public byte[] serialize() {
return filter.getSerializedFormat();
}
public ByteBuffer toBuffer() {
return filter.toBuffer();
}
// the logarithm of the base used for various calculations
private static double logB() {
return log1p(-1.0/m);
}
}