Skip to content

Commit 983f687

Browse files
authored
perf: optimize bloom filter hashing (#1811)
1 parent e9c6594 commit 983f687

File tree

5 files changed

+28
-42
lines changed

5 files changed

+28
-42
lines changed

Cargo.lock

Lines changed: 11 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

program-libs/bloom-filter/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pinocchio = ["dep:pinocchio"]
1212

1313
[dependencies]
1414
bitvec = "1.0.1"
15-
fastmurmur3 = "0.2.0"
15+
solana-nostd-keccak = "0.1.3"
1616
num-bigint = { workspace = true }
1717
solana-program-error = { workspace = true, optional = true }
1818
pinocchio = { workspace = true, optional = true }

program-libs/bloom-filter/src/lib.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,20 @@ impl<'a> BloomFilter<'a> {
6868
})
6969
}
7070

71-
pub fn probe_index_fast_murmur(value_bytes: &[u8], iteration: usize, capacity: &u64) -> usize {
72-
let iter_bytes = iteration.to_le_bytes();
73-
let base_hash = fastmurmur3::hash(value_bytes);
74-
let mut combined_bytes = [0u8; 24];
75-
combined_bytes[..16].copy_from_slice(&base_hash.to_le_bytes());
76-
combined_bytes[16..].copy_from_slice(&iter_bytes);
71+
pub fn probe_index_keccak(value_bytes: &[u8; 32], iteration: usize, capacity: &u64) -> usize {
72+
let iter_bytes: [u8; 8] = iteration.to_le_bytes();
73+
let mut combined_bytes = [0u8; 40];
74+
combined_bytes[..32].copy_from_slice(value_bytes);
75+
combined_bytes[32..].copy_from_slice(&iter_bytes);
7776

78-
let combined_hash = fastmurmur3::hash(&combined_bytes);
79-
(combined_hash % (*capacity as u128)) as usize
77+
let hash = solana_nostd_keccak::hash(&combined_bytes);
78+
79+
let mut index = 0u64;
80+
for chunk in hash.chunks(8) {
81+
let value = u64::from_le_bytes(chunk.try_into().unwrap());
82+
index = value.wrapping_add(index) % *capacity;
83+
}
84+
index as usize
8085
}
8186

8287
pub fn insert(&mut self, value: &[u8; 32]) -> Result<(), BloomFilterError> {
@@ -98,7 +103,7 @@ impl<'a> BloomFilter<'a> {
98103

99104
let bits = BitSlice::<u8, Msb0>::from_slice_mut(self.store);
100105
for i in 0..self.num_iters {
101-
let probe_index = Self::probe_index_fast_murmur(value, i, &(self.capacity));
106+
let probe_index = Self::probe_index_keccak(value, i, &(self.capacity));
102107
if bits[probe_index] {
103108
continue;
104109
} else if insert {

program-libs/hasher/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ solana-program-error = { workspace = true, optional = true }
2323
solana-pubkey = { workspace = true, optional = true }
2424
pinocchio = { workspace = true, optional = true }
2525
borsh = { workspace = true }
26+
solana-nostd-keccak = "0.1.3"
2627

2728
[target.'cfg(not(target_os = "solana"))'.dependencies]
2829
ark-bn254 = { workspace = true }

program-libs/hasher/src/keccak.rs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,7 @@ impl Hasher for Keccak {
1414
}
1515

1616
fn hashv(vals: &[&[u8]]) -> Result<Hash, HasherError> {
17-
#[cfg(not(target_os = "solana"))]
18-
{
19-
use sha3::{Digest, Keccak256};
20-
21-
let mut hasher = Keccak256::default();
22-
for val in vals {
23-
hasher.update(val);
24-
}
25-
Ok(hasher.finalize().into())
26-
}
27-
// Call via a system call to perform the calculation
28-
#[cfg(target_os = "solana")]
29-
{
30-
use crate::HASH_BYTES;
31-
32-
let mut hash_result = [0; HASH_BYTES];
33-
unsafe {
34-
crate::syscalls::sol_keccak256(
35-
vals as *const _ as *const u8,
36-
vals.len() as u64,
37-
&mut hash_result as *mut _ as *mut u8,
38-
);
39-
}
40-
Ok(hash_result)
41-
}
17+
Ok(solana_nostd_keccak::hashv(vals))
4218
}
4319

4420
fn zero_bytes() -> ZeroBytes {

0 commit comments

Comments
 (0)