@libp2p/utils 5.3.2-998fcaf94 → 5.3.2-e1923b0a7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/bloom-filter.d.ts +33 -0
- package/dist/src/bloom-filter.d.ts.map +1 -0
- package/dist/src/bloom-filter.js +113 -0
- package/dist/src/bloom-filter.js.map +1 -0
- package/package.json +14 -7
- package/src/bloom-filter.ts +141 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface BloomFilterOptions {
|
|
2
|
+
seeds?: number[];
|
|
3
|
+
hashes?: number;
|
|
4
|
+
bits?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class BloomFilter {
|
|
7
|
+
/**
|
|
8
|
+
* Create a `BloomFilter` with the smallest `bits` and `hashes` value for the
|
|
9
|
+
* specified item count and error rate.
|
|
10
|
+
*/
|
|
11
|
+
static create(itemcount: number, errorRate?: number): BloomFilter;
|
|
12
|
+
readonly seeds: number[];
|
|
13
|
+
readonly bits: number;
|
|
14
|
+
buffer: Uint8Array;
|
|
15
|
+
constructor(options?: BloomFilterOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Add an item to the filter
|
|
18
|
+
*/
|
|
19
|
+
add(item: Uint8Array | string): void;
|
|
20
|
+
/**
|
|
21
|
+
* Test if the filter has an item. If it returns false it definitely does not
|
|
22
|
+
* have the item. If it returns true, it probably has the item but there's
|
|
23
|
+
* an `errorRate` chance it doesn't.
|
|
24
|
+
*/
|
|
25
|
+
has(item: Uint8Array | string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Reset the filter
|
|
28
|
+
*/
|
|
29
|
+
clear(): void;
|
|
30
|
+
setbit(bit: number): void;
|
|
31
|
+
getbit(bit: number): boolean;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=bloom-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bloom-filter.d.ts","sourceRoot":"","sources":["../../src/bloom-filter.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,qBAAa,WAAW;IACtB;;;OAGG;IACH,MAAM,CAAC,MAAM,CAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,MAAc,GAAG,WAAW;IAKzE,SAAgB,KAAK,EAAE,MAAM,EAAE,CAAA;IAC/B,SAAgB,IAAI,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,UAAU,CAAA;gBAEZ,OAAO,GAAE,kBAAuB;IAW7C;;OAEG;IACH,GAAG,CAAE,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI;IAarC;;;;OAIG;IACH,GAAG,CAAE,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO;IAmBxC;;OAEG;IACH,KAAK,IAAK,IAAI;IAId,MAAM,CAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAa1B,MAAM,CAAE,GAAG,EAAE,MAAM,GAAG,OAAO;CAW9B"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// ported from xxbloom - https://github.com/ceejbot/xxbloom/blob/master/LICENSE
|
|
2
|
+
import { randomBytes } from '@libp2p/crypto';
|
|
3
|
+
import mur from 'murmurhash3js-revisited';
|
|
4
|
+
import { Uint8ArrayList } from 'uint8arraylist';
|
|
5
|
+
import { alloc } from 'uint8arrays/alloc';
|
|
6
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
|
|
7
|
+
const LN2_SQUARED = Math.LN2 * Math.LN2;
|
|
8
|
+
export class BloomFilter {
|
|
9
|
+
/**
|
|
10
|
+
* Create a `BloomFilter` with the smallest `bits` and `hashes` value for the
|
|
11
|
+
* specified item count and error rate.
|
|
12
|
+
*/
|
|
13
|
+
static create(itemcount, errorRate = 0.005) {
|
|
14
|
+
const opts = optimize(itemcount, errorRate);
|
|
15
|
+
return new BloomFilter(opts);
|
|
16
|
+
}
|
|
17
|
+
seeds;
|
|
18
|
+
bits;
|
|
19
|
+
buffer;
|
|
20
|
+
constructor(options = {}) {
|
|
21
|
+
if (options.seeds != null) {
|
|
22
|
+
this.seeds = options.seeds;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
this.seeds = generateSeeds(options.hashes ?? 8);
|
|
26
|
+
}
|
|
27
|
+
this.bits = options.bits ?? 1024;
|
|
28
|
+
this.buffer = alloc(Math.ceil(this.bits / 8));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Add an item to the filter
|
|
32
|
+
*/
|
|
33
|
+
add(item) {
|
|
34
|
+
if (typeof item === 'string') {
|
|
35
|
+
item = uint8ArrayFromString(item);
|
|
36
|
+
}
|
|
37
|
+
for (let i = 0; i < this.seeds.length; i++) {
|
|
38
|
+
const hash = mur.x86.hash32(item, this.seeds[i]);
|
|
39
|
+
const bit = hash % this.bits;
|
|
40
|
+
this.setbit(bit);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Test if the filter has an item. If it returns false it definitely does not
|
|
45
|
+
* have the item. If it returns true, it probably has the item but there's
|
|
46
|
+
* an `errorRate` chance it doesn't.
|
|
47
|
+
*/
|
|
48
|
+
has(item) {
|
|
49
|
+
if (typeof item === 'string') {
|
|
50
|
+
item = uint8ArrayFromString(item);
|
|
51
|
+
}
|
|
52
|
+
for (let i = 0; i < this.seeds.length; i++) {
|
|
53
|
+
const hash = mur.x86.hash32(item, this.seeds[i]);
|
|
54
|
+
const bit = hash % this.bits;
|
|
55
|
+
const isSet = this.getbit(bit);
|
|
56
|
+
if (!isSet) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Reset the filter
|
|
64
|
+
*/
|
|
65
|
+
clear() {
|
|
66
|
+
this.buffer.fill(0);
|
|
67
|
+
}
|
|
68
|
+
setbit(bit) {
|
|
69
|
+
let pos = 0;
|
|
70
|
+
let shift = bit;
|
|
71
|
+
while (shift > 7) {
|
|
72
|
+
pos++;
|
|
73
|
+
shift -= 8;
|
|
74
|
+
}
|
|
75
|
+
let bitfield = this.buffer[pos];
|
|
76
|
+
bitfield |= (0x1 << shift);
|
|
77
|
+
this.buffer[pos] = bitfield;
|
|
78
|
+
}
|
|
79
|
+
getbit(bit) {
|
|
80
|
+
let pos = 0;
|
|
81
|
+
let shift = bit;
|
|
82
|
+
while (shift > 7) {
|
|
83
|
+
pos++;
|
|
84
|
+
shift -= 8;
|
|
85
|
+
}
|
|
86
|
+
const bitfield = this.buffer[pos];
|
|
87
|
+
return (bitfield & (0x1 << shift)) !== 0;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function optimize(itemcount, errorRate = 0.005) {
|
|
91
|
+
const bits = Math.round(-1 * itemcount * Math.log(errorRate) / LN2_SQUARED);
|
|
92
|
+
const hashes = Math.round((bits / itemcount) * Math.LN2);
|
|
93
|
+
return { bits, hashes };
|
|
94
|
+
}
|
|
95
|
+
function generateSeeds(count) {
|
|
96
|
+
let buf;
|
|
97
|
+
let j;
|
|
98
|
+
const seeds = [];
|
|
99
|
+
for (let i = 0; i < count; i++) {
|
|
100
|
+
buf = new Uint8ArrayList(randomBytes(4));
|
|
101
|
+
seeds[i] = buf.getUint32(0, true);
|
|
102
|
+
// Make sure we don't end up with two identical seeds,
|
|
103
|
+
// which is unlikely but possible.
|
|
104
|
+
for (j = 0; j < i; j++) {
|
|
105
|
+
if (seeds[i] === seeds[j]) {
|
|
106
|
+
i--;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return seeds;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=bloom-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bloom-filter.js","sourceRoot":"","sources":["../../src/bloom-filter.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libp2p/utils",
|
|
3
|
-
"version": "5.3.2-
|
|
3
|
+
"version": "5.3.2-e1923b0a7",
|
|
4
4
|
"description": "Package to aggregate shared logic and dependencies for the libp2p ecosystem",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/utils#readme",
|
|
@@ -56,6 +56,10 @@
|
|
|
56
56
|
"types": "./dist/src/array-equals.d.ts",
|
|
57
57
|
"import": "./dist/src/array-equals.js"
|
|
58
58
|
},
|
|
59
|
+
"./bloom-filter": {
|
|
60
|
+
"types": "./dist/src/bloom-filter.d.ts",
|
|
61
|
+
"import": "./dist/src/bloom-filter.js"
|
|
62
|
+
},
|
|
59
63
|
"./close-source": {
|
|
60
64
|
"types": "./dist/src/close-source.d.ts",
|
|
61
65
|
"import": "./dist/src/close-source.js"
|
|
@@ -128,23 +132,27 @@
|
|
|
128
132
|
},
|
|
129
133
|
"dependencies": {
|
|
130
134
|
"@chainsafe/is-ip": "^2.0.2",
|
|
131
|
-
"@libp2p/
|
|
132
|
-
"@libp2p/
|
|
135
|
+
"@libp2p/crypto": "4.1.0-e1923b0a7",
|
|
136
|
+
"@libp2p/interface": "1.3.0-e1923b0a7",
|
|
137
|
+
"@libp2p/logger": "4.0.11-e1923b0a7",
|
|
133
138
|
"@multiformats/multiaddr": "^12.2.1",
|
|
134
139
|
"@multiformats/multiaddr-matcher": "^1.2.0",
|
|
140
|
+
"@types/murmurhash3js-revisited": "^3.0.3",
|
|
135
141
|
"delay": "^6.0.0",
|
|
136
142
|
"get-iterator": "^2.0.1",
|
|
137
143
|
"is-loopback-addr": "^2.0.2",
|
|
138
144
|
"it-pushable": "^3.2.3",
|
|
139
145
|
"it-stream-types": "^2.0.1",
|
|
146
|
+
"murmurhash3js-revisited": "^3.0.0",
|
|
140
147
|
"netmask": "^2.0.2",
|
|
141
148
|
"p-defer": "^4.0.1",
|
|
142
149
|
"race-event": "^1.2.0",
|
|
143
150
|
"race-signal": "^1.0.2",
|
|
144
|
-
"uint8arraylist": "^2.4.8"
|
|
151
|
+
"uint8arraylist": "^2.4.8",
|
|
152
|
+
"uint8arrays": "^5.0.3"
|
|
145
153
|
},
|
|
146
154
|
"devDependencies": {
|
|
147
|
-
"@libp2p/peer-id-factory": "4.1.0-
|
|
155
|
+
"@libp2p/peer-id-factory": "4.1.0-e1923b0a7",
|
|
148
156
|
"@types/netmask": "^2.0.5",
|
|
149
157
|
"aegir": "^42.2.5",
|
|
150
158
|
"delay": "^6.0.0",
|
|
@@ -153,8 +161,7 @@
|
|
|
153
161
|
"it-pair": "^2.0.6",
|
|
154
162
|
"it-pipe": "^3.0.1",
|
|
155
163
|
"sinon": "^17.0.1",
|
|
156
|
-
"sinon-ts": "^2.0.0"
|
|
157
|
-
"uint8arrays": "^5.0.3"
|
|
164
|
+
"sinon-ts": "^2.0.0"
|
|
158
165
|
},
|
|
159
166
|
"sideEffects": false
|
|
160
167
|
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// ported from xxbloom - https://github.com/ceejbot/xxbloom/blob/master/LICENSE
|
|
2
|
+
import { randomBytes } from '@libp2p/crypto'
|
|
3
|
+
import mur from 'murmurhash3js-revisited'
|
|
4
|
+
import { Uint8ArrayList } from 'uint8arraylist'
|
|
5
|
+
import { alloc } from 'uint8arrays/alloc'
|
|
6
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
7
|
+
|
|
8
|
+
const LN2_SQUARED = Math.LN2 * Math.LN2
|
|
9
|
+
|
|
10
|
+
export interface BloomFilterOptions {
|
|
11
|
+
seeds?: number[]
|
|
12
|
+
hashes?: number
|
|
13
|
+
bits?: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class BloomFilter {
|
|
17
|
+
/**
|
|
18
|
+
* Create a `BloomFilter` with the smallest `bits` and `hashes` value for the
|
|
19
|
+
* specified item count and error rate.
|
|
20
|
+
*/
|
|
21
|
+
static create (itemcount: number, errorRate: number = 0.005): BloomFilter {
|
|
22
|
+
const opts = optimize(itemcount, errorRate)
|
|
23
|
+
return new BloomFilter(opts)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public readonly seeds: number[]
|
|
27
|
+
public readonly bits: number
|
|
28
|
+
public buffer: Uint8Array
|
|
29
|
+
|
|
30
|
+
constructor (options: BloomFilterOptions = {}) {
|
|
31
|
+
if (options.seeds != null) {
|
|
32
|
+
this.seeds = options.seeds
|
|
33
|
+
} else {
|
|
34
|
+
this.seeds = generateSeeds(options.hashes ?? 8)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
this.bits = options.bits ?? 1024
|
|
38
|
+
this.buffer = alloc(Math.ceil(this.bits / 8))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Add an item to the filter
|
|
43
|
+
*/
|
|
44
|
+
add (item: Uint8Array | string): void {
|
|
45
|
+
if (typeof item === 'string') {
|
|
46
|
+
item = uint8ArrayFromString(item)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (let i = 0; i < this.seeds.length; i++) {
|
|
50
|
+
const hash = mur.x86.hash32(item, this.seeds[i])
|
|
51
|
+
const bit = hash % this.bits
|
|
52
|
+
|
|
53
|
+
this.setbit(bit)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Test if the filter has an item. If it returns false it definitely does not
|
|
59
|
+
* have the item. If it returns true, it probably has the item but there's
|
|
60
|
+
* an `errorRate` chance it doesn't.
|
|
61
|
+
*/
|
|
62
|
+
has (item: Uint8Array | string): boolean {
|
|
63
|
+
if (typeof item === 'string') {
|
|
64
|
+
item = uint8ArrayFromString(item)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for (let i = 0; i < this.seeds.length; i++) {
|
|
68
|
+
const hash = mur.x86.hash32(item, this.seeds[i])
|
|
69
|
+
const bit = hash % this.bits
|
|
70
|
+
|
|
71
|
+
const isSet = this.getbit(bit)
|
|
72
|
+
|
|
73
|
+
if (!isSet) {
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return true
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Reset the filter
|
|
83
|
+
*/
|
|
84
|
+
clear (): void {
|
|
85
|
+
this.buffer.fill(0)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
setbit (bit: number): void {
|
|
89
|
+
let pos = 0
|
|
90
|
+
let shift = bit
|
|
91
|
+
while (shift > 7) {
|
|
92
|
+
pos++
|
|
93
|
+
shift -= 8
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let bitfield = this.buffer[pos]
|
|
97
|
+
bitfield |= (0x1 << shift)
|
|
98
|
+
this.buffer[pos] = bitfield
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
getbit (bit: number): boolean {
|
|
102
|
+
let pos = 0
|
|
103
|
+
let shift = bit
|
|
104
|
+
while (shift > 7) {
|
|
105
|
+
pos++
|
|
106
|
+
shift -= 8
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const bitfield = this.buffer[pos]
|
|
110
|
+
return (bitfield & (0x1 << shift)) !== 0
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function optimize (itemcount: number, errorRate: number = 0.005): { bits: number, hashes: number } {
|
|
115
|
+
const bits = Math.round(-1 * itemcount * Math.log(errorRate) / LN2_SQUARED)
|
|
116
|
+
const hashes = Math.round((bits / itemcount) * Math.LN2)
|
|
117
|
+
|
|
118
|
+
return { bits, hashes }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function generateSeeds (count: number): number[] {
|
|
122
|
+
let buf: Uint8ArrayList
|
|
123
|
+
let j: number
|
|
124
|
+
const seeds = []
|
|
125
|
+
|
|
126
|
+
for (let i = 0; i < count; i++) {
|
|
127
|
+
buf = new Uint8ArrayList(randomBytes(4))
|
|
128
|
+
seeds[i] = buf.getUint32(0, true)
|
|
129
|
+
|
|
130
|
+
// Make sure we don't end up with two identical seeds,
|
|
131
|
+
// which is unlikely but possible.
|
|
132
|
+
for (j = 0; j < i; j++) {
|
|
133
|
+
if (seeds[i] === seeds[j]) {
|
|
134
|
+
i--
|
|
135
|
+
break
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return seeds
|
|
141
|
+
}
|