@qbix/q 1.0.5

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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +678 -0
  3. package/dist/Metrics.js +2873 -0
  4. package/dist/Metrics.min.js +95 -0
  5. package/dist/Q.js +15677 -0
  6. package/dist/Q.min.js +385 -0
  7. package/dist/Q.minimal.js +11594 -0
  8. package/dist/Q.minimal.min.js +286 -0
  9. package/dist/handlebars-v4.0.10.min.js +29 -0
  10. package/dist/handlebars.minimal.min.js +1 -0
  11. package/dist/img/hints/rotate-left.gif +0 -0
  12. package/dist/img/hints/swipe-down.gif +0 -0
  13. package/dist/img/hints/swipe-up.gif +0 -0
  14. package/dist/img/hints/tap.gif +0 -0
  15. package/dist/img/throbbers/loading.gif +0 -0
  16. package/dist/jquery.minimal.min.js +18 -0
  17. package/dist/methods/Q/Audio/load.js +29 -0
  18. package/dist/methods/Q/Audio/loadVoices.js +36 -0
  19. package/dist/methods/Q/Audio/play.js +47 -0
  20. package/dist/methods/Q/Audio/speak.js +149 -0
  21. package/dist/methods/Q/Crypto/delegate.js +186 -0
  22. package/dist/methods/Q/Crypto/internalKeypair.js +170 -0
  23. package/dist/methods/Q/Crypto/sign.js +200 -0
  24. package/dist/methods/Q/Crypto/verify.js +212 -0
  25. package/dist/methods/Q/Crypto/verifyDelegated.js +214 -0
  26. package/dist/methods/Q/Data/Bloom/_internal.js +163 -0
  27. package/dist/methods/Q/Data/Bloom/create.js +23 -0
  28. package/dist/methods/Q/Data/Bloom/fromBase64.js +21 -0
  29. package/dist/methods/Q/Data/Bloom/fromBytes.js +15 -0
  30. package/dist/methods/Q/Data/Bloom/fromElements.js +33 -0
  31. package/dist/methods/Q/Data/Merkle/_internal.js +68 -0
  32. package/dist/methods/Q/Data/Merkle/build.js +29 -0
  33. package/dist/methods/Q/Data/Merkle/proof.js +50 -0
  34. package/dist/methods/Q/Data/Merkle/verify.js +32 -0
  35. package/dist/methods/Q/Data/Prolly/_internal.js +190 -0
  36. package/dist/methods/Q/Data/Prolly/build.js +28 -0
  37. package/dist/methods/Q/Data/Prolly/delete.js +28 -0
  38. package/dist/methods/Q/Data/Prolly/diff.js +70 -0
  39. package/dist/methods/Q/Data/Prolly/get.js +38 -0
  40. package/dist/methods/Q/Data/Prolly/set.js +32 -0
  41. package/dist/methods/Q/Data/compress.js +45 -0
  42. package/dist/methods/Q/Data/decompress.js +35 -0
  43. package/dist/methods/Q/Data/decrypt.js +55 -0
  44. package/dist/methods/Q/Data/derive.js +76 -0
  45. package/dist/methods/Q/Data/digest.js +29 -0
  46. package/dist/methods/Q/Data/encrypt.js +61 -0
  47. package/dist/methods/Q/Data/generateKey.js +40 -0
  48. package/dist/methods/Q/Data/hkdf.js +44 -0
  49. package/dist/methods/Q/Data/importKey.js +34 -0
  50. package/dist/methods/Q/Data/sign.js +42 -0
  51. package/dist/methods/Q/Data/verify.js +45 -0
  52. package/dist/methods/Q/Onboarding/handle.js +50 -0
  53. package/dist/methods/Q/Onboarding/start.js +165 -0
  54. package/dist/methods/Q/Onboarding/stop.js +21 -0
  55. package/dist/methods/Q/Sandbox/run.js +392 -0
  56. package/dist/methods/Q/Tool/define/component.js +218 -0
  57. package/dist/methods/Q/globalMemoryWalk.js +82 -0
  58. package/dist/methods/Q/leaves.js +34 -0
  59. package/dist/methods/Q/registerWebComponent.js +0 -0
  60. package/dist/methods/Q/sanitize.js +142 -0
  61. package/dist/test.html +6 -0
  62. package/dist/tools/Q/lazyload.js +433 -0
  63. package/package.json +26 -0
@@ -0,0 +1,212 @@
1
+ Q.exports(function (Q) {
2
+
3
+ /**
4
+ * Verify typed signatures (Q-native or EIP-712).
5
+ *
6
+ * Always returns a boolean.
7
+ *
8
+ * Optional recovery:
9
+ * - If options.recovered is an object, recovered signer info
10
+ * will be written into it (when supported by the format).
11
+ *
12
+ * @static
13
+ * @method verify
14
+ * @param {Object} options
15
+ * @param {String} [options.format='ES256']
16
+ * @param {Object} options.domain
17
+ * @param {Object} options.types
18
+ * @param {Object} options.message
19
+ * @param {String|Uint8Array} options.signature
20
+ * @param {String} [options.address] Expected signer address (EIP712)
21
+ * @param {Uint8Array} [options.publicKey] Expected signer public key (ES256)
22
+ * @param {Object} [options.recovered] If provided, signer info is written here
23
+ * @return {Q.Promise} resolves to true or false
24
+ */
25
+ return function Q_Crypto_verify(options) {
26
+
27
+ return new Q.Promise(async function (resolve) {
28
+
29
+ if (!options) {
30
+ throw new Error("options required");
31
+ }
32
+
33
+ const format = options.format || "ES256";
34
+
35
+ /* =================================================
36
+ * Ethereum / EIP-712
37
+ * ================================================= */
38
+ if (format === "EIP712") {
39
+
40
+ if (typeof options.primaryType !== "string") {
41
+ throw new Error("primaryType required for eip712 verification");
42
+ }
43
+
44
+ let recoveredAddress;
45
+
46
+ // Prefer ethers if available (ecosystem parity)
47
+ if (
48
+ globalThis.ethers &&
49
+ typeof globalThis.ethers.verifyTypedData === "function"
50
+ ) {
51
+ try {
52
+ recoveredAddress = globalThis.ethers.verifyTypedData(
53
+ options.domain || {},
54
+ options.types,
55
+ options.message,
56
+ options.signature
57
+ );
58
+ } catch (e) {
59
+ resolve(false);
60
+ return;
61
+ }
62
+
63
+ } else {
64
+
65
+ // Spec-correct fallback
66
+ try {
67
+ const [{ hashTypedData }, { keccak_256 }] = await Promise.all([
68
+ import(Q.url("{{Q}}/src/js/crypto/eip712.js")),
69
+ import(Q.url("{{Q}}/src/js/crypto/sha3.js"))
70
+ ]);
71
+
72
+ const digest = hashTypedData(
73
+ options.domain || {},
74
+ options.primaryType,
75
+ options.message,
76
+ options.types
77
+ );
78
+
79
+ const secp = await import(
80
+ Q.url("{{Q}}/src/js/crypto/secp256k1.js")
81
+ );
82
+
83
+ let sigBytes = options.signature;
84
+
85
+ if (typeof sigBytes === "string") {
86
+ sigBytes = Q.Data.fromHex(sigBytes);
87
+ }
88
+
89
+ if (!(sigBytes instanceof Uint8Array)) {
90
+ resolve(false);
91
+ return;
92
+ }
93
+
94
+ // Accept 65-byte RSV → drop v
95
+ if (sigBytes.length === 65) {
96
+ sigBytes = sigBytes.slice(0, 64);
97
+ }
98
+
99
+ if (sigBytes.length !== 64) {
100
+ resolve(false);
101
+ return;
102
+ }
103
+
104
+ const sig = secp.secp256k1.Signature.fromCompact(sigBytes);
105
+
106
+ // Enforce low-s (EIP-2)
107
+ if (sig.s > secp.secp256k1.CURVE.n / 2n) {
108
+ resolve(false);
109
+ return;
110
+ }
111
+
112
+ const pub = sig
113
+ .recoverPublicKey(digest)
114
+ .toRawBytes(false); // uncompressed
115
+
116
+ if (!secp.secp256k1.verify(sig, digest, pub)) {
117
+ resolve(false);
118
+ return;
119
+ }
120
+
121
+ // Address = last 20 bytes of keccak(pub[1:])
122
+ const addrBytes = keccak_256(pub.slice(1)).slice(-20);
123
+ recoveredAddress =
124
+ "0x" +
125
+ [...addrBytes].map(b =>
126
+ b.toString(16).padStart(2, "0")
127
+ ).join("");
128
+
129
+ } catch (e) {
130
+ resolve(false);
131
+ return;
132
+ }
133
+ }
134
+
135
+ if (options.recovered && typeof options.recovered === "object") {
136
+ options.recovered.address = recoveredAddress;
137
+ }
138
+
139
+ if (options.address) {
140
+ resolve(
141
+ recoveredAddress.toLowerCase() ===
142
+ options.address.toLowerCase()
143
+ );
144
+ return;
145
+ }
146
+
147
+ resolve(true);
148
+ return;
149
+ }
150
+
151
+ /* =================================================
152
+ * es256 (P-256 + SHA-256)
153
+ * =================================================
154
+ *
155
+ * es256 signatures are DER-encoded ECDSA (WebCrypto compatible)
156
+ */
157
+ if (format === "ES256") {
158
+
159
+ if (!(options.publicKey instanceof Uint8Array)) {
160
+ throw new Error("ES256 verify requires publicKey (Uint8Array)");
161
+ }
162
+ if (!(options.signature instanceof Uint8Array)) {
163
+ throw new Error("ES256 verify requires signature (Uint8Array)");
164
+ }
165
+
166
+ const payload = {
167
+ domain: options.domain || {},
168
+ primaryType: options.primaryType,
169
+ types: options.types,
170
+ message: options.message
171
+ };
172
+
173
+ // Deep canonicalization (must match sign.js)
174
+ const canonical = Q.serialize(payload);
175
+ const data = new TextEncoder().encode(canonical);
176
+
177
+ try {
178
+ const digestBytes = await Q.Data.digest("SHA-256", data);
179
+
180
+ const key = await crypto.subtle.importKey(
181
+ "raw",
182
+ options.publicKey,
183
+ { name: "ECDSA", namedCurve: "P-256" },
184
+ false,
185
+ ["verify"]
186
+ );
187
+
188
+ try {
189
+ const ok = await crypto.subtle.verify(
190
+ { name: "ECDSA", hash: "SHA-256" },
191
+ key,
192
+ options.signature, // DER-encoded ECDSA
193
+ digestBytes
194
+ );
195
+ resolve(ok);
196
+ } catch (e) {
197
+ resolve(false);
198
+ }
199
+
200
+ return;
201
+
202
+ } catch (e) {
203
+ resolve(false);
204
+ return;
205
+ }
206
+ }
207
+
208
+ throw new Error("Unknown signature format: " + format);
209
+ });
210
+ };
211
+
212
+ });
@@ -0,0 +1,214 @@
1
+ Q.exports(function (Q) {
2
+
3
+ /**
4
+ * Verify a single delegation step.
5
+ *
6
+ * Verifies exactly ONE level of delegation. Intended to be called
7
+ * repeatedly to validate a delegation chain.
8
+ *
9
+ * Guarantees:
10
+ * - The derived secret matches `statement.secretHash`
11
+ * - The delegation statement was correctly signed
12
+ * - The signer matches the parent identity declared in the statement
13
+ *
14
+ * Does NOT verify:
15
+ * - Parent legitimacy beyond this step
16
+ * - Expiration or revocation policy
17
+ *
18
+ * Secret hash algorithm matches the signing format:
19
+ * - EIP712 → keccak256(derivedSecret)
20
+ * - ES256 → SHA-256(derivedSecret)
21
+ * This must match delegate.js exactly.
22
+ *
23
+ * @static
24
+ * @method verifyDelegated
25
+ *
26
+ * @param {Object} options
27
+ * @param {String} [options.format="ES256"] "ES256" or "EIP712".
28
+ * @param {Object} options.statement Delegation statement.
29
+ * @param {String|Uint8Array} options.signature Signature bytes.
30
+ * @param {Uint8Array} options.derivedSecret Derived child secret.
31
+ * @param {Uint8Array} [options.parentPublicKey] Expected parent key (ES256).
32
+ * @param {Object} [options.domain] EIP-712 domain (EIP712 only).
33
+ * @param {Object} [options.recovered] Optional recovered signer output.
34
+ *
35
+ * @return {Q.Promise<Boolean>}
36
+ */
37
+ return function Q_Crypto_verifyDelegated(options) {
38
+
39
+ return new Q.Promise(function (resolve, reject) {
40
+
41
+ try {
42
+
43
+ if (!options) {
44
+ throw new Error("options required");
45
+ }
46
+
47
+ const format = options.format || "ES256";
48
+ const statement = options.statement;
49
+ const derivedSecret = options.derivedSecret;
50
+
51
+ // -------------------------------------------------
52
+ // Validate inputs
53
+ // -------------------------------------------------
54
+ if (!statement || typeof statement !== "object") {
55
+ throw new Error("statement required");
56
+ }
57
+ if (!(derivedSecret instanceof Uint8Array)) {
58
+ throw new Error("derivedSecret must be Uint8Array");
59
+ }
60
+ if (typeof statement.parent !== "string") {
61
+ throw new Error("statement.parent required");
62
+ }
63
+ if (typeof statement.label !== "string") {
64
+ throw new Error("statement.label required");
65
+ }
66
+ if (typeof statement.issuedTime !== "number") {
67
+ throw new Error("statement.issuedTime required");
68
+ }
69
+ if (typeof statement.secretHash !== "string") {
70
+ throw new Error("statement.secretHash required");
71
+ }
72
+ if ("context" in statement && typeof statement.context !== "string") {
73
+ throw new Error("statement.context must be string when present");
74
+ }
75
+
76
+ const context = statement.context || "";
77
+
78
+ // -------------------------------------------------
79
+ // Verify secret binding
80
+ // Algorithm matches delegate.js: keccak256 for EIP712, SHA-256 for ES256
81
+ // -------------------------------------------------
82
+ const secretHashPromise = format === "EIP712"
83
+ ? import(Q.url("{{Q}}/src/js/crypto/sha3.js"))
84
+ .then(function ({ keccak_256 }) {
85
+ return Q.Data.toHex(keccak_256(derivedSecret));
86
+ })
87
+ : Q.Data.digest("SHA-256", derivedSecret)
88
+ .then(function (h) {
89
+ return Q.Data.toHex(h);
90
+ });
91
+
92
+ secretHashPromise.then(function (actualSecretHashHex) {
93
+
94
+ if (actualSecretHashHex !== statement.secretHash) {
95
+ resolve(false);
96
+ return;
97
+ }
98
+
99
+ // -------------------------------------------------
100
+ // Schema — must match delegate.js types exactly
101
+ // -------------------------------------------------
102
+ const types = {
103
+ EIP712Domain: [
104
+ { name: "name", type: "string" },
105
+ { name: "version", type: "string" },
106
+ { name: "salt", type: "bytes32" }
107
+ ],
108
+ Delegation: [
109
+ {
110
+ name: "parent",
111
+ type: format === "EIP712" ? "address" : "bytes32"
112
+ },
113
+ { name: "label", type: "string" },
114
+ { name: "issuedTime", type: "uint64" },
115
+ { name: "context", type: "string" },
116
+ { name: "secretHash", type: "bytes32" }
117
+ ]
118
+ };
119
+
120
+ // -------------------------------------------------
121
+ // Normalize signature
122
+ // -------------------------------------------------
123
+ let signature = options.signature;
124
+ if (typeof signature === "string") {
125
+ signature = Q.Data.fromBase64(signature);
126
+ }
127
+
128
+ // -------------------------------------------------
129
+ // EIP712 path
130
+ // -------------------------------------------------
131
+ if (format === "EIP712") {
132
+
133
+ return Q.Crypto.verify({
134
+ format: "EIP712",
135
+ domain: options.domain || {},
136
+ types: types,
137
+ primaryType: "Delegation",
138
+ message: Q.extend({}, statement, { context: context }),
139
+ signature: signature,
140
+ recovered: options.recovered
141
+ }).then(function (verified) {
142
+
143
+ if (!verified) {
144
+ resolve(false);
145
+ return;
146
+ }
147
+
148
+ const recoveredAddress =
149
+ options.recovered && options.recovered.address;
150
+
151
+ if (
152
+ !recoveredAddress ||
153
+ recoveredAddress.toLowerCase() !==
154
+ statement.parent.toLowerCase()
155
+ ) {
156
+ resolve(false);
157
+ return;
158
+ }
159
+
160
+ resolve(true);
161
+ });
162
+ }
163
+
164
+ // -------------------------------------------------
165
+ // ES256 path
166
+ // -------------------------------------------------
167
+ if (!(options.parentPublicKey instanceof Uint8Array)) {
168
+ throw new Error("parentPublicKey required for ES256");
169
+ }
170
+
171
+ const pubBytes = Q.Data.toUint8Array(options.parentPublicKey);
172
+
173
+ return Q.Data.digest("SHA-256", pubBytes)
174
+ .then(function (digest) {
175
+
176
+ const expectedParent = Q.Data.toHex(digest);
177
+
178
+ if (expectedParent !== statement.parent) {
179
+ resolve(false);
180
+ return;
181
+ }
182
+
183
+ return Q.Crypto.verify({
184
+ format: "ES256",
185
+ domain: options.domain || {},
186
+ types: types,
187
+ primaryType: "Delegation",
188
+ message: Q.extend({}, statement, { context: context }),
189
+ signature: signature,
190
+ publicKey: pubBytes
191
+ }).then(function (verified) {
192
+
193
+ if (!verified) {
194
+ resolve(false);
195
+ return;
196
+ }
197
+
198
+ if (options.recovered && typeof options.recovered === "object") {
199
+ options.recovered.publicKey = pubBytes;
200
+ }
201
+
202
+ resolve(true);
203
+ });
204
+ });
205
+
206
+ }).catch(reject);
207
+
208
+ } catch (e) {
209
+ reject(e);
210
+ }
211
+ });
212
+ };
213
+
214
+ });
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Shared helpers for Q.Data.Bloom method files.
3
+ * Loaded once via options.require and passed as _ to each method file.
4
+ *
5
+ * Exports a plain object containing:
6
+ * - BloomFilter constructor (used by all four method files)
7
+ * - _positions, _optimalParams, _setBit, _testBit, _fromUint8Array
8
+ */
9
+ Q.exports(function (Q) {
10
+
11
+ var LN2 = Math.LN2;
12
+ var LN2S = LN2 * LN2;
13
+
14
+ // -------------------------------------------------------------------------
15
+ // Sizing
16
+ // -------------------------------------------------------------------------
17
+
18
+ function _optimalParams(n, p) {
19
+ var m = Math.ceil(-n * Math.log(p) / LN2S);
20
+ var k = Math.max(1, Math.round((m / n) * LN2));
21
+ return { m: m, k: k };
22
+ }
23
+
24
+ // -------------------------------------------------------------------------
25
+ // Bit array ops
26
+ // -------------------------------------------------------------------------
27
+
28
+ function _setBit(bits, pos) { bits[pos >>> 3] |= (1 << (pos & 7)); }
29
+ function _testBit(bits, pos) { return (bits[pos >>> 3] & (1 << (pos & 7))) !== 0; }
30
+
31
+ // -------------------------------------------------------------------------
32
+ // Kirsch-Mitzenmacher double hashing
33
+ // Two SHA-256 calls -> k positions, as effective as k independent hashes.
34
+ // h_i(x) = (h1(x) + i * h2(x)) mod m
35
+ // -------------------------------------------------------------------------
36
+
37
+ function _positions(element, k, m) {
38
+ var enc = new TextEncoder();
39
+ return Promise.all([
40
+ Q.Data.digest('SHA-256', enc.encode('\x00' + element)),
41
+ Q.Data.digest('SHA-256', enc.encode('\x01' + element))
42
+ ]).then(function (digests) {
43
+ var view = function (d) {
44
+ return ((d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3]) >>> 0;
45
+ };
46
+ var h1 = view(digests[0]);
47
+ var h2 = view(digests[1]);
48
+ var positions = [];
49
+ for (var i = 0; i < k; i++) {
50
+ var combined = ((h1 >>> 0) + Math.imul(i, h2 >>> 0)) >>> 0;
51
+ positions.push(combined % m);
52
+ }
53
+ return positions;
54
+ });
55
+ }
56
+
57
+ // -------------------------------------------------------------------------
58
+ // BloomFilter class
59
+ // -------------------------------------------------------------------------
60
+
61
+ function BloomFilter(bits, k, m, count) {
62
+ this._bits = bits;
63
+ this._k = k;
64
+ this._m = m;
65
+ this._count = count || 0;
66
+ }
67
+
68
+ BloomFilter.prototype.add = Q.promisify(function (element, callback) {
69
+ var self = this;
70
+ _positions(element, self._k, self._m).then(function (positions) {
71
+ positions.forEach(function (pos) { _setBit(self._bits, pos); });
72
+ self._count++;
73
+ callback(null);
74
+ }).catch(callback);
75
+ }, false, 1);
76
+
77
+ BloomFilter.prototype.has = Q.promisify(function (element, callback) {
78
+ var self = this;
79
+ _positions(element, self._k, self._m).then(function (positions) {
80
+ callback(null, positions.every(function (pos) { return _testBit(self._bits, pos); }));
81
+ }).catch(callback);
82
+ }, false, 1);
83
+
84
+ BloomFilter.prototype.hasMany = Q.promisify(function (elements, callback) {
85
+ var self = this;
86
+ Promise.all(elements.map(function (el) {
87
+ return _positions(el, self._k, self._m).then(function (positions) {
88
+ return positions.every(function (pos) { return _testBit(self._bits, pos); });
89
+ });
90
+ })).then(function (results) {
91
+ callback(null, results);
92
+ }).catch(callback);
93
+ }, false, 1);
94
+
95
+ BloomFilter.prototype.merge = Q.promisify(function (other, callback) {
96
+ if (other._m !== this._m || other._k !== this._k) {
97
+ return callback(new Error('Q.Data.Bloom.merge: incompatible filters'));
98
+ }
99
+ for (var i = 0; i < this._bits.length; i++) {
100
+ this._bits[i] |= other._bits[i];
101
+ }
102
+ this._count += other._count;
103
+ callback(null);
104
+ }, false, 1);
105
+
106
+ BloomFilter.prototype.falsePositiveRate = function () {
107
+ return Math.pow(1 - Math.exp(-this._k * this._count / this._m), this._k);
108
+ };
109
+
110
+ BloomFilter.prototype.elementCount = function () { return this._count; };
111
+
112
+ BloomFilter.prototype.toBytes = function () {
113
+ var out = new Uint8Array(9 + this._bits.length);
114
+ out[0] = (this._m >>> 24) & 0xff;
115
+ out[1] = (this._m >>> 16) & 0xff;
116
+ out[2] = (this._m >>> 8) & 0xff;
117
+ out[3] = this._m & 0xff;
118
+ out[4] = this._k & 0xff;
119
+ out[5] = (this._count >>> 24) & 0xff;
120
+ out[6] = (this._count >>> 16) & 0xff;
121
+ out[7] = (this._count >>> 8) & 0xff;
122
+ out[8] = this._count & 0xff;
123
+ out.set(this._bits, 9);
124
+ return out;
125
+ };
126
+
127
+ BloomFilter.prototype.toBase64 = function () {
128
+ return Q.Data.toBase64(this.toBytes());
129
+ };
130
+
131
+ // -------------------------------------------------------------------------
132
+ // Deserialise helper shared by fromBytes + fromBase64
133
+ // -------------------------------------------------------------------------
134
+
135
+ function _fromUint8Array(bytes, callback) {
136
+ if (bytes.length < 9) {
137
+ return callback(new Error('Q.Data.Bloom: buffer too short'));
138
+ }
139
+ var view = function (d, o) { return ((d[o] << 24) | (d[o+1] << 16) | (d[o+2] << 8) | d[o+3]) >>> 0; };
140
+ var m = view(bytes, 0);
141
+ var k = bytes[4];
142
+ var count = view(bytes, 5);
143
+ var bits = new Uint8Array(bytes.buffer, bytes.byteOffset + 9);
144
+ if (bits.length < Math.ceil(m / 8)) {
145
+ return callback(new Error('Q.Data.Bloom: truncated bit array'));
146
+ }
147
+ callback(null, new BloomFilter(new Uint8Array(bits), k, m, count));
148
+ }
149
+
150
+ // -------------------------------------------------------------------------
151
+ // Exported helpers object
152
+ // -------------------------------------------------------------------------
153
+
154
+ return {
155
+ BloomFilter: BloomFilter,
156
+ optimalParams: _optimalParams,
157
+ positions: _positions,
158
+ setBit: _setBit,
159
+ testBit: _testBit,
160
+ fromUint8Array: _fromUint8Array
161
+ };
162
+
163
+ });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Q.Data.Bloom.create
3
+ * Create a new empty Bloom filter sized for n elements at false positive rate p.
4
+ *
5
+ * @param {Number} n
6
+ * @param {Number} [p=0.01]
7
+ * @param {Function} [callback] (err, BloomFilter)
8
+ * @return {Q.Promise<BloomFilter>}
9
+ */
10
+ Q.exports(function (Q, _) {
11
+
12
+ return Q.promisify(function (n, p, callback) {
13
+ if (typeof p === 'function') { callback = p; p = 0.01; }
14
+ p = p || 0.01;
15
+ if (n <= 0) { return callback(new Error('Q.Data.Bloom.create: n must be > 0')); }
16
+ if (p <= 0 || p >= 1) { return callback(new Error('Q.Data.Bloom.create: p must be in (0,1)')); }
17
+
18
+ var params = _.optimalParams(n, p);
19
+ var bits = new Uint8Array(Math.ceil(params.m / 8));
20
+ callback(null, new _.BloomFilter(bits, params.k, params.m, 0));
21
+ }, false, 2);
22
+
23
+ });
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Q.Data.Bloom.fromBase64
3
+ * Deserialise a BloomFilter from a base64 string produced by filter.toBase64().
4
+ *
5
+ * @param {String} base64
6
+ * @param {Function} [callback] (err, BloomFilter)
7
+ * @return {Q.Promise<BloomFilter>}
8
+ */
9
+ Q.exports(function (Q, _) {
10
+
11
+ return Q.promisify(function (base64, callback) {
12
+ var bytes;
13
+ try {
14
+ bytes = Q.Data.fromBase64(base64);
15
+ } catch (e) {
16
+ return callback(e);
17
+ }
18
+ _.fromUint8Array(bytes, callback);
19
+ }, false, 1);
20
+
21
+ });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Q.Data.Bloom.fromBytes
3
+ * Deserialise a BloomFilter from a Uint8Array produced by filter.toBytes().
4
+ *
5
+ * @param {Uint8Array} bytes
6
+ * @param {Function} [callback] (err, BloomFilter)
7
+ * @return {Q.Promise<BloomFilter>}
8
+ */
9
+ Q.exports(function (Q, _) {
10
+
11
+ return Q.promisify(function (bytes, callback) {
12
+ _.fromUint8Array(bytes, callback);
13
+ }, false, 1);
14
+
15
+ });
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Q.Data.Bloom.fromElements
3
+ * Build a Bloom filter from an existing array of elements in one call.
4
+ * All SHA-256 calls run in parallel for speed.
5
+ *
6
+ * @param {Array<String>} elements
7
+ * @param {Number} [p=0.01]
8
+ * @param {Function} [callback] (err, BloomFilter)
9
+ * @return {Q.Promise<BloomFilter>}
10
+ */
11
+ Q.exports(function (Q, _) {
12
+
13
+ return Q.promisify(function (elements, p, callback) {
14
+ if (typeof p === 'function') { callback = p; p = 0.01; }
15
+ p = p || 0.01;
16
+
17
+ if (!elements || !elements.length) {
18
+ return callback(new Error('Q.Data.Bloom.fromElements: no elements provided'));
19
+ }
20
+
21
+ var params = _.optimalParams(elements.length, p);
22
+ var bits = new Uint8Array(Math.ceil(params.m / 8));
23
+
24
+ Promise.all(elements.map(function (el) {
25
+ return _.positions(el, params.k, params.m).then(function (positions) {
26
+ positions.forEach(function (pos) { _.setBit(bits, pos); });
27
+ });
28
+ })).then(function () {
29
+ callback(null, new _.BloomFilter(bits, params.k, params.m, elements.length));
30
+ }).catch(callback);
31
+ }, false, 2);
32
+
33
+ });