Last active
October 18, 2023 14:27
-
-
Save trophygeek/d67ecb90cdb5f093313757d9e0d7f46e to your computer and use it in GitHub Desktop.
Simple and easy to understand bloom filter in javascript for the browser. Uses BigInts and crypto.subtle.digest in 29 lines
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
Simple and fast bloom filter (about 40 lines of actual code) | |
Uses build-in hash and BigInts to do work. Hash requires async/await | |
Meant for use in browser code not node | |
used like this: | |
// add to bloom | |
const bloomFilter = new BloomFilter(); | |
bloomFilter.loadSaved(); // optional loading from localstorage | |
await bloomFilter.add("test1"); | |
await bloomFilter.add("test2"); | |
... | |
// check for values later | |
const found = await.bloomFilter.contains("test1"); // MAY be in bloom | |
const notFound = await.bloomFilter.contains("test3"); // Definitely NOT in bloom | |
... | |
bloomFilter.save(); // optional save | |
**/ | |
class BloomFilter { | |
// may use 'SHA-256' for better distribution | |
constructor(shaStr='SHA-1') { | |
this.bloomBigInt = BigInt(0); | |
this.encoder = new TextEncoder(); // performance | |
this.shaStr = shaStr; | |
} | |
async hash(item) { | |
// hash into buffer | |
const hashBuffer = await crypto.subtle.digest(this.shaStr, // e.g.'SHA-1' | |
this.encoder.encode(item)); | |
// hash buffer to bigint passes through hex string. must be a better way? | |
const hashArray = Array.from(new Uint8Array(hashBuffer)); | |
const hashHex = hashArray | |
.map((b) => b.toString(16).padStart(2, "0")) | |
.join(""); | |
return BigInt(`0x${hashHex}`); | |
} | |
async add(item) { | |
const bn = await this.hash(item); | |
this.bloomBigInt = bn | this.bloomBigInt; | |
} | |
async contains(item) { | |
const bn = await this.hash(item); | |
return (bn & this.bloomBigInt) === bn; | |
} | |
// the save/restore could use some work | |
save() { | |
localStorage.setItem(`bloomSha1`, this.bloomBigInt.toString()); | |
} | |
loadSaved() { | |
const loadedBitsStr = localStorage.getItem(`bloomSha1`) || ''; | |
if (loadedBitsStr?.length) { | |
this.bloomBigInt = BigInt(loadedBitsStr); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment