Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
805b5e2
[cryptography] move bloomfilter to module dir
andresilva Jan 7, 2026
46b7c42
[cryptography/bloomfilter] add benchmark
andresilva Jan 7, 2026
2e17353
[cryptopgrahy/bloomfilter] make number of bits a power of two
andresilva Jan 7, 2026
e81e11a
[cryptography/bloomfilter] fix tests
andresilva Jan 7, 2026
73d90c2
[cryptography/bloomfilter] stats
andresilva Jan 7, 2026
a2cadf8
[cryptography/bloomfilter] tighten
andresilva Jan 7, 2026
0b8b08b
[cryptography/bloomfilter] fix arbitrary instance
andresilva Jan 7, 2026
04ae331
[cryptography] conformance
andresilva Jan 7, 2026
e23979c
[cryptography/bloomfilter] fix no_std
andresilva Jan 7, 2026
5589649
[cryptography/bloomfilter] validate false_positive_rate
andresilva Jan 7, 2026
2cb54e5
[cryptography/bloomfilter] make sure h2 is non-zero
andresilva Jan 8, 2026
b4ea449
[cryptography/bloomfilter] generic over Hasher
andresilva Jan 8, 2026
58cb70d
[cryptography/bloomfilter] better benchmarks
andresilva Jan 8, 2026
ccf34ce
[cryptography/bloomfilter] lighter benches
andresilva Jan 8, 2026
6063bc5
[cryptography/bloomfilter] lint
andresilva Jan 8, 2026
d74c06f
[cryptography/bloomfilter] fix fuzzer input
andresilva Jan 8, 2026
adae91c
[cryptography/bloomfilter] add getters for bits and hashers
andresilva Jan 8, 2026
1d84f4a
[cryptography/bloomfilter] fuzz with_rate constructor
andresilva Jan 8, 2026
c94b14a
[cryptography/bloomfilter] Read validates that bits is power of two
andresilva Jan 8, 2026
700db56
[cryptography/bloomfilter] fuzz fixes
andresilva Jan 8, 2026
f69fc9c
[cryptography/bloomfilter] expected items is NonZeroUsize
andresilva Jan 8, 2026
e131f6b
[cryptography/bloomfilter] fix overflow
andresilva Jan 8, 2026
52888a8
[cryptography/bloomfilter] fix arbitrary
andresilva Jan 8, 2026
a0e0a3c
[cryptography/bloomfilter] update conformance
andresilva Jan 8, 2026
e049669
standardize benchmark format
patrick-ogrady Jan 9, 2026
98191f4
[cryptography/bloomfilter] fmt
andresilva Jan 9, 2026
f130dde
[cryptography/bloomfilter] use integer math only
andresilva Jan 9, 2026
5eeb208
[cryptography/bloomfilter] docs
andresilva Jan 9, 2026
9999706
[cryptography/bloomfilter] fix no_std
andresilva Jan 9, 2026
b6adff7
[cryptography/bloomfilter] fix overflow
andresilva Jan 9, 2026
9c83383
[cryptography/bloomfilter] lint
andresilva Jan 9, 2026
39df4d2
[cryptography/bloomfilter] no_std
andresilva Jan 9, 2026
9994592
[cryptography/bloomfilter] conformance test
andresilva Jan 9, 2026
cd4768f
[cryptography/bloomfilter] fmt
andresilva Jan 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cryptography/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,8 @@ path = "src/lthash/benches/bench.rs"
name = "handshake"
harness = false
path = "src/handshake/benches/bench.rs"

[[bench]]
name = "bloomfilter"
harness = false
path = "src/bloomfilter/benches/bench.rs"
8 changes: 6 additions & 2 deletions cryptography/conformance.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
n_cases = 65536
hash = "c0501d4a691d1fccec7c5906e8608228569d24164150edd215838593e3b77512"

["commonware_cryptography::bloomfilter::tests::conformance::CodecConformance<BloomFilter>"]
["commonware_cryptography::bloomfilter::conformance::CodecConformance<BloomFilter>"]
n_cases = 65536
hash = "a75d6312366816126114abdc9d7fbd246891cab210eeae6a02781625aa1ad6a4"
hash = "698dac6cf35fcd1557a962e7215da4251d7e42f68a2331b70ff0dd542c4116dd"

["commonware_cryptography::bloomfilter::conformance::FpRateBuckets"]
n_cases = 1024
hash = "723f3a5fd8b147f722d5fa990f39b3ffd6a2f0df46d00dcb1e294647b565eb85"

["commonware_cryptography::bls12381::certificate::multisig::tests::conformance::CodecConformance<Certificate<MinSig>>"]
n_cases = 65536
Expand Down
67 changes: 55 additions & 12 deletions cryptography/fuzz/fuzz_targets/bloomfilter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

use arbitrary::Arbitrary;
use commonware_codec::{Decode, Encode, EncodeSize};
use commonware_cryptography::BloomFilter;
use commonware_cryptography::{sha256::Sha256, BloomFilter};
use libfuzzer_sys::fuzz_target;
use std::{
collections::HashSet,
num::{NonZeroU16, NonZeroU8},
num::{NonZeroU16, NonZeroU8, NonZeroUsize},
};

#[derive(Arbitrary, Debug)]
Expand All @@ -18,30 +18,73 @@ enum Op {
EncodeSize,
}

#[derive(Debug)]
enum Constructor {
New {
hashers: NonZeroU8,
bits: NonZeroU16,
},
WithRate {
expected_items: NonZeroU16,
fp_rate: f64,
},
}

impl<'a> Arbitrary<'a> for Constructor {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
if u.arbitrary::<bool>()? {
let hashers = u.arbitrary()?;
// Fallback to highest power of two in u16 on overflow
let bits = u
.arbitrary::<u16>()?
.checked_next_power_of_two()
.and_then(NonZeroU16::new)
.unwrap_or(NonZeroU16::new(1 << 15).unwrap());
Ok(Constructor::New { hashers, bits })
} else {
let expected_items = u.arbitrary::<NonZeroU16>()?;
// Generate f64 in range (0.0, 1.0) exclusive
let fp_rate = u.int_in_range(1u32..=u32::MAX - 1)? as f64 / u32::MAX as f64;
Ok(Constructor::WithRate {
expected_items,
fp_rate,
})
}
}
}

const MAX_OPERATIONS: usize = 64;

#[derive(Debug)]
struct FuzzInput {
hashers: NonZeroU8,
bits: NonZeroU16,
constructor: Constructor,
ops: Vec<Op>,
}

impl<'a> Arbitrary<'a> for FuzzInput {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let hashers = u.arbitrary()?;
let bits = u.arbitrary()?;
let constructor = u.arbitrary()?;
let num_ops = u.int_in_range(1..=MAX_OPERATIONS)?;
let ops = (0..num_ops)
.map(|_| Op::arbitrary(u))
.collect::<Result<Vec<_>, _>>()?;
Ok(FuzzInput { hashers, bits, ops })
Ok(FuzzInput { constructor, ops })
}
}

fn fuzz(input: FuzzInput) {
let cfg = (input.hashers, input.bits.into());
let mut bf = BloomFilter::new(input.hashers, input.bits.into());
let mut bf = match input.constructor {
Constructor::New { hashers, bits } => BloomFilter::<Sha256>::new(hashers, bits.into()),
Constructor::WithRate {
expected_items,
fp_rate,
} => BloomFilter::<Sha256>::with_rate(
NonZeroUsize::new(expected_items.get() as usize).unwrap(),
fp_rate,
),
};

let cfg = (bf.hashers(), bf.bits().try_into().unwrap());
let mut model: HashSet<Vec<u8>> = HashSet::new();

for op in input.ops {
Expand All @@ -58,11 +101,11 @@ fn fuzz(input: FuzzInput) {
}
Op::DecodeCfg(data, hashers, bits) => {
let cfg = (hashers, bits.into());
_ = BloomFilter::decode_cfg(&data[..], &cfg);
_ = BloomFilter::<Sha256>::decode_cfg(&data[..], &cfg);
}
Op::Encode(_item) => {
let encoded = bf.encode();
let decoded = BloomFilter::decode_cfg(encoded.clone(), &cfg).unwrap();
let decoded = BloomFilter::<Sha256>::decode_cfg(encoded.clone(), &cfg).unwrap();
assert_eq!(bf, decoded);

let encode_size = bf.encode_size();
Expand All @@ -80,7 +123,7 @@ fn fuzz(input: FuzzInput) {
"encode_size should match encode().len()"
);

let decoded = BloomFilter::decode_cfg(encoded, &cfg).unwrap();
let decoded = BloomFilter::<Sha256>::decode_cfg(encoded, &cfg).unwrap();
assert_eq!(bf, decoded);

assert_eq!(decoded.encode_size(), size1);
Expand Down
Loading
Loading