@aleph-ai/tinyaleph 1.3.0 → 1.4.1
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/README.md +423 -12
- package/backends/cryptographic/index.js +455 -2
- package/core/beacon.js +735 -0
- package/core/crt-homology.js +1004 -0
- package/core/enochian-vocabulary.js +910 -0
- package/core/enochian.js +744 -0
- package/core/errors.js +587 -0
- package/core/hilbert.js +651 -1
- package/core/index.js +86 -1
- package/core/lambda.js +284 -33
- package/core/logger.js +350 -0
- package/core/prime.js +136 -1
- package/core/quaternion-semantics.js +623 -0
- package/core/reduction.js +391 -1
- package/core/rformer-crt.js +892 -0
- package/core/topology.js +655 -0
- package/docs/README.md +54 -0
- package/docs/design/PYTHON_PORT_DESIGN.md +1400 -0
- package/docs/reference/07-topology.md +257 -0
- package/docs/reference/08-observer.md +421 -0
- package/docs/reference/09-crt-homology.md +369 -0
- package/modular.js +231 -3
- package/package.json +1 -1
package/core/beacon.js
ADDED
|
@@ -0,0 +1,735 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Beacon System for Prime-Resonant Data Transfer
|
|
3
|
+
*
|
|
4
|
+
* From "How Data Summoning Works" paper:
|
|
5
|
+
* Instead of sending files directly, the system encodes data into
|
|
6
|
+
* resonance beacons that can be used to reconstruct the original
|
|
7
|
+
* information through non-local quantum-like processes.
|
|
8
|
+
*
|
|
9
|
+
* Key concepts:
|
|
10
|
+
* - ResonantFragment: Prime coefficient mappings for holographic encoding
|
|
11
|
+
* - Beacon: Compact pointer for file discovery and reconstruction
|
|
12
|
+
* - Chinese Remainder Theorem for reconstruction
|
|
13
|
+
* - Hilbert space mapping
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const crypto = require('crypto');
|
|
17
|
+
const { isPrime, primesUpTo, factorize } = require('./prime');
|
|
18
|
+
const { Complex, PrimeState } = require('./hilbert');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Resonant Fragment
|
|
22
|
+
*
|
|
23
|
+
* A fragment of resonant information encoded using prime coefficients.
|
|
24
|
+
*
|
|
25
|
+
* interface ResonantFragment {
|
|
26
|
+
* coeffs: Map<number, number>; // Prime coefficient mappings
|
|
27
|
+
* center: [number, number]; // Hilbert space coordinates
|
|
28
|
+
* entropy: number; // Information density measure
|
|
29
|
+
* index: number[]; // Prime indices for reconstruction
|
|
30
|
+
* epoch: number; // Temporal versioning
|
|
31
|
+
* fingerprint: Uint8Array; // Cryptographic hash
|
|
32
|
+
* signature: Uint8Array; // Authentication signature
|
|
33
|
+
* }
|
|
34
|
+
*/
|
|
35
|
+
class ResonantFragment {
|
|
36
|
+
/**
|
|
37
|
+
* Create a resonant fragment
|
|
38
|
+
* @param {Object} options - Configuration
|
|
39
|
+
*/
|
|
40
|
+
constructor(options = {}) {
|
|
41
|
+
// Prime coefficient mappings
|
|
42
|
+
this.coeffs = options.coeffs || new Map();
|
|
43
|
+
|
|
44
|
+
// Hilbert space coordinates (2D projection)
|
|
45
|
+
this.center = options.center || [0, 0];
|
|
46
|
+
|
|
47
|
+
// Information density (entropy)
|
|
48
|
+
this.entropy = options.entropy || 0;
|
|
49
|
+
|
|
50
|
+
// Prime indices for reconstruction
|
|
51
|
+
this.index = options.index || [];
|
|
52
|
+
|
|
53
|
+
// Version/epoch
|
|
54
|
+
this.epoch = options.epoch || Date.now();
|
|
55
|
+
|
|
56
|
+
// Cryptographic fingerprint
|
|
57
|
+
this.fingerprint = options.fingerprint || null;
|
|
58
|
+
|
|
59
|
+
// Authentication signature
|
|
60
|
+
this.signature = options.signature || null;
|
|
61
|
+
|
|
62
|
+
// Source metadata
|
|
63
|
+
this.metadata = options.metadata || {};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Encode data into a resonant fragment using prime decomposition
|
|
68
|
+
*
|
|
69
|
+
* @param {Buffer|string} data - Data to encode
|
|
70
|
+
* @param {Array<number>} primes - Prime basis to use
|
|
71
|
+
* @returns {ResonantFragment} Encoded fragment
|
|
72
|
+
*/
|
|
73
|
+
static fromData(data, primes = null) {
|
|
74
|
+
const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
75
|
+
const defaultPrimes = primes || primesUpTo(256).slice(0, 64);
|
|
76
|
+
|
|
77
|
+
const fragment = new ResonantFragment();
|
|
78
|
+
fragment.index = defaultPrimes;
|
|
79
|
+
|
|
80
|
+
// Compute prime coefficients using modular arithmetic
|
|
81
|
+
// c_i = Σ_j data[j] * p_i^j mod M
|
|
82
|
+
const M = BigInt('1000000007'); // Large prime modulus
|
|
83
|
+
|
|
84
|
+
for (const p of defaultPrimes) {
|
|
85
|
+
let coeff = 0n;
|
|
86
|
+
let power = 1n;
|
|
87
|
+
const bp = BigInt(p);
|
|
88
|
+
|
|
89
|
+
for (let j = 0; j < buffer.length; j++) {
|
|
90
|
+
coeff = (coeff + BigInt(buffer[j]) * power) % M;
|
|
91
|
+
power = (power * bp) % M;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
fragment.coeffs.set(p, Number(coeff));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Compute Hilbert space center from first two dominant coefficients
|
|
98
|
+
const sortedCoeffs = [...fragment.coeffs.entries()]
|
|
99
|
+
.sort((a, b) => b[1] - a[1]);
|
|
100
|
+
|
|
101
|
+
if (sortedCoeffs.length >= 2) {
|
|
102
|
+
const maxCoeff = Math.max(...sortedCoeffs.map(c => c[1])) || 1;
|
|
103
|
+
fragment.center = [
|
|
104
|
+
sortedCoeffs[0][1] / maxCoeff,
|
|
105
|
+
sortedCoeffs[1][1] / maxCoeff
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Compute entropy from coefficient distribution
|
|
110
|
+
const totalCoeff = [...fragment.coeffs.values()].reduce((s, c) => s + c, 0);
|
|
111
|
+
if (totalCoeff > 0) {
|
|
112
|
+
let h = 0;
|
|
113
|
+
for (const coeff of fragment.coeffs.values()) {
|
|
114
|
+
const p = coeff / totalCoeff;
|
|
115
|
+
if (p > 0) {
|
|
116
|
+
h -= p * Math.log2(p);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
fragment.entropy = h;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Compute fingerprint
|
|
123
|
+
fragment.fingerprint = crypto.createHash('sha256').update(buffer).digest();
|
|
124
|
+
|
|
125
|
+
return fragment;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Convert fragment to PrimeState representation
|
|
130
|
+
*/
|
|
131
|
+
toPrimeState() {
|
|
132
|
+
const state = new PrimeState(this.index);
|
|
133
|
+
|
|
134
|
+
const maxCoeff = Math.max(...this.coeffs.values()) || 1;
|
|
135
|
+
|
|
136
|
+
for (const [p, coeff] of this.coeffs) {
|
|
137
|
+
// Normalize coefficient to amplitude
|
|
138
|
+
const amplitude = coeff / maxCoeff;
|
|
139
|
+
// Phase from coefficient mod 2π
|
|
140
|
+
const phase = (2 * Math.PI * coeff) / 1000000007;
|
|
141
|
+
|
|
142
|
+
state.set(p, Complex.fromPolar(amplitude, phase));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return state.normalize();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Compute resonance strength with another fragment
|
|
150
|
+
* @param {ResonantFragment} other - Other fragment
|
|
151
|
+
*/
|
|
152
|
+
resonanceWith(other) {
|
|
153
|
+
let dot = 0;
|
|
154
|
+
let norm1 = 0;
|
|
155
|
+
let norm2 = 0;
|
|
156
|
+
|
|
157
|
+
for (const p of this.index) {
|
|
158
|
+
const c1 = this.coeffs.get(p) || 0;
|
|
159
|
+
const c2 = other.coeffs.get(p) || 0;
|
|
160
|
+
dot += c1 * c2;
|
|
161
|
+
norm1 += c1 * c1;
|
|
162
|
+
norm2 += c2 * c2;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const denom = Math.sqrt(norm1) * Math.sqrt(norm2);
|
|
166
|
+
return denom > 0 ? dot / denom : 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Serialize fragment
|
|
171
|
+
*/
|
|
172
|
+
toJSON() {
|
|
173
|
+
return {
|
|
174
|
+
coeffs: Array.from(this.coeffs.entries()),
|
|
175
|
+
center: this.center,
|
|
176
|
+
entropy: this.entropy,
|
|
177
|
+
index: this.index,
|
|
178
|
+
epoch: this.epoch,
|
|
179
|
+
fingerprint: this.fingerprint ? this.fingerprint.toString('hex') : null,
|
|
180
|
+
signature: this.signature ? this.signature.toString('hex') : null,
|
|
181
|
+
metadata: this.metadata
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Deserialize fragment
|
|
187
|
+
*/
|
|
188
|
+
static fromJSON(data) {
|
|
189
|
+
const fragment = new ResonantFragment({
|
|
190
|
+
center: data.center,
|
|
191
|
+
entropy: data.entropy,
|
|
192
|
+
index: data.index,
|
|
193
|
+
epoch: data.epoch,
|
|
194
|
+
metadata: data.metadata
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
fragment.coeffs = new Map(data.coeffs);
|
|
198
|
+
|
|
199
|
+
if (data.fingerprint) {
|
|
200
|
+
fragment.fingerprint = Buffer.from(data.fingerprint, 'hex');
|
|
201
|
+
}
|
|
202
|
+
if (data.signature) {
|
|
203
|
+
fragment.signature = Buffer.from(data.signature, 'hex');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return fragment;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Beacon
|
|
212
|
+
*
|
|
213
|
+
* Compact pointer that enables file discovery and reconstruction.
|
|
214
|
+
* Contains minimal information needed to summon the original data.
|
|
215
|
+
*/
|
|
216
|
+
class Beacon {
|
|
217
|
+
/**
|
|
218
|
+
* Create a beacon
|
|
219
|
+
* @param {Object} options - Configuration
|
|
220
|
+
*/
|
|
221
|
+
constructor(options = {}) {
|
|
222
|
+
this.id = options.id || Beacon.generateId();
|
|
223
|
+
this.type = options.type || 'fragment';
|
|
224
|
+
this.authorId = options.authorId || null;
|
|
225
|
+
|
|
226
|
+
// Core resonance data
|
|
227
|
+
this.primeIndices = options.primeIndices || ''; // Encoded prime sequence
|
|
228
|
+
this.epoch = options.epoch || Date.now();
|
|
229
|
+
|
|
230
|
+
// Verification
|
|
231
|
+
this.fingerprint = options.fingerprint || null;
|
|
232
|
+
this.signature = options.signature || null;
|
|
233
|
+
|
|
234
|
+
// Metadata
|
|
235
|
+
this.metadata = options.metadata || {};
|
|
236
|
+
this.createdAt = options.createdAt || new Date().toISOString();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Generate unique beacon ID
|
|
241
|
+
*/
|
|
242
|
+
static generateId() {
|
|
243
|
+
return `bcn_${Date.now().toString(36)}_${crypto.randomBytes(8).toString('hex')}`;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Create beacon from resonant fragment
|
|
248
|
+
* @param {ResonantFragment} fragment - Source fragment
|
|
249
|
+
* @param {Object} options - Additional options
|
|
250
|
+
*/
|
|
251
|
+
static fromFragment(fragment, options = {}) {
|
|
252
|
+
const beacon = new Beacon({
|
|
253
|
+
type: options.type || 'fragment',
|
|
254
|
+
authorId: options.authorId,
|
|
255
|
+
epoch: fragment.epoch,
|
|
256
|
+
fingerprint: fragment.fingerprint,
|
|
257
|
+
metadata: options.metadata
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Encode prime indices compactly
|
|
261
|
+
// Use top-k coefficients by magnitude
|
|
262
|
+
const topK = options.topK || 16;
|
|
263
|
+
const sortedPrimes = [...fragment.coeffs.entries()]
|
|
264
|
+
.sort((a, b) => b[1] - a[1])
|
|
265
|
+
.slice(0, topK)
|
|
266
|
+
.map(([p]) => p);
|
|
267
|
+
|
|
268
|
+
// Delta encoding for compression
|
|
269
|
+
beacon.primeIndices = Beacon.encodePrimes(sortedPrimes);
|
|
270
|
+
|
|
271
|
+
return beacon;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Encode primes using delta + base64
|
|
276
|
+
*/
|
|
277
|
+
static encodePrimes(primes) {
|
|
278
|
+
if (primes.length === 0) return '';
|
|
279
|
+
|
|
280
|
+
const deltas = [primes[0]];
|
|
281
|
+
for (let i = 1; i < primes.length; i++) {
|
|
282
|
+
deltas.push(primes[i] - primes[i - 1]);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Pack as varints
|
|
286
|
+
const buffer = Buffer.alloc(primes.length * 4);
|
|
287
|
+
let offset = 0;
|
|
288
|
+
|
|
289
|
+
for (const d of deltas) {
|
|
290
|
+
buffer.writeInt32LE(d, offset);
|
|
291
|
+
offset += 4;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return buffer.slice(0, offset).toString('base64');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Decode primes from encoded string
|
|
299
|
+
*/
|
|
300
|
+
static decodePrimes(encoded) {
|
|
301
|
+
if (!encoded) return [];
|
|
302
|
+
|
|
303
|
+
const buffer = Buffer.from(encoded, 'base64');
|
|
304
|
+
const deltas = [];
|
|
305
|
+
|
|
306
|
+
for (let i = 0; i < buffer.length; i += 4) {
|
|
307
|
+
deltas.push(buffer.readInt32LE(i));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Reconstruct from deltas
|
|
311
|
+
const primes = [];
|
|
312
|
+
let current = 0;
|
|
313
|
+
|
|
314
|
+
for (const d of deltas) {
|
|
315
|
+
current += d;
|
|
316
|
+
primes.push(current);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return primes;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Get decoded prime indices
|
|
324
|
+
*/
|
|
325
|
+
getPrimes() {
|
|
326
|
+
return Beacon.decodePrimes(this.primeIndices);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Verify fingerprint matches
|
|
331
|
+
* @param {Buffer} data - Original data to verify
|
|
332
|
+
*/
|
|
333
|
+
verify(data) {
|
|
334
|
+
if (!this.fingerprint) return false;
|
|
335
|
+
|
|
336
|
+
const hash = crypto.createHash('sha256').update(data).digest();
|
|
337
|
+
return hash.equals(this.fingerprint);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Serialize beacon
|
|
342
|
+
*/
|
|
343
|
+
toJSON() {
|
|
344
|
+
return {
|
|
345
|
+
id: this.id,
|
|
346
|
+
type: this.type,
|
|
347
|
+
authorId: this.authorId,
|
|
348
|
+
primeIndices: this.primeIndices,
|
|
349
|
+
epoch: this.epoch,
|
|
350
|
+
fingerprint: this.fingerprint ? this.fingerprint.toString('hex') : null,
|
|
351
|
+
signature: this.signature ? this.signature.toString('hex') : null,
|
|
352
|
+
metadata: this.metadata,
|
|
353
|
+
createdAt: this.createdAt
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Deserialize beacon
|
|
359
|
+
*/
|
|
360
|
+
static fromJSON(data) {
|
|
361
|
+
const beacon = new Beacon({
|
|
362
|
+
id: data.id,
|
|
363
|
+
type: data.type,
|
|
364
|
+
authorId: data.authorId,
|
|
365
|
+
primeIndices: data.primeIndices,
|
|
366
|
+
epoch: data.epoch,
|
|
367
|
+
metadata: data.metadata,
|
|
368
|
+
createdAt: data.createdAt
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
if (data.fingerprint) {
|
|
372
|
+
beacon.fingerprint = Buffer.from(data.fingerprint, 'hex');
|
|
373
|
+
}
|
|
374
|
+
if (data.signature) {
|
|
375
|
+
beacon.signature = Buffer.from(data.signature, 'hex');
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return beacon;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Beacon Cache Manager
|
|
384
|
+
*
|
|
385
|
+
* Client-side caching system for beacons.
|
|
386
|
+
*/
|
|
387
|
+
class BeaconCache {
|
|
388
|
+
constructor(options = {}) {
|
|
389
|
+
// L1: In-memory cache
|
|
390
|
+
this.cache = new Map();
|
|
391
|
+
|
|
392
|
+
// L2: User-indexed beacons
|
|
393
|
+
this.userIndex = new Map();
|
|
394
|
+
|
|
395
|
+
// L3: Type-indexed beacons
|
|
396
|
+
this.typeIndex = new Map();
|
|
397
|
+
|
|
398
|
+
// Cache limits
|
|
399
|
+
this.maxSize = options.maxSize || 1000;
|
|
400
|
+
|
|
401
|
+
// LRU tracking
|
|
402
|
+
this.accessOrder = [];
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Store a beacon
|
|
407
|
+
* @param {Beacon} beacon - Beacon to store
|
|
408
|
+
*/
|
|
409
|
+
set(beacon) {
|
|
410
|
+
// Update access order
|
|
411
|
+
this.touch(beacon.id);
|
|
412
|
+
|
|
413
|
+
// Store in main cache
|
|
414
|
+
this.cache.set(beacon.id, beacon);
|
|
415
|
+
|
|
416
|
+
// Index by user
|
|
417
|
+
if (beacon.authorId) {
|
|
418
|
+
if (!this.userIndex.has(beacon.authorId)) {
|
|
419
|
+
this.userIndex.set(beacon.authorId, new Set());
|
|
420
|
+
}
|
|
421
|
+
this.userIndex.get(beacon.authorId).add(beacon.id);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Index by type
|
|
425
|
+
if (!this.typeIndex.has(beacon.type)) {
|
|
426
|
+
this.typeIndex.set(beacon.type, new Set());
|
|
427
|
+
}
|
|
428
|
+
this.typeIndex.get(beacon.type).add(beacon.id);
|
|
429
|
+
|
|
430
|
+
// Evict if over capacity
|
|
431
|
+
this.evict();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Get beacon by ID
|
|
436
|
+
* @param {string} id - Beacon ID
|
|
437
|
+
*/
|
|
438
|
+
get(id) {
|
|
439
|
+
const beacon = this.cache.get(id);
|
|
440
|
+
if (beacon) {
|
|
441
|
+
this.touch(id);
|
|
442
|
+
}
|
|
443
|
+
return beacon;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Get beacons by user
|
|
448
|
+
* @param {string} userId - User ID
|
|
449
|
+
*/
|
|
450
|
+
getByUser(userId) {
|
|
451
|
+
const ids = this.userIndex.get(userId);
|
|
452
|
+
if (!ids) return [];
|
|
453
|
+
|
|
454
|
+
return [...ids].map(id => this.get(id)).filter(Boolean);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Get beacons by type
|
|
459
|
+
* @param {string} type - Beacon type
|
|
460
|
+
*/
|
|
461
|
+
getByType(type) {
|
|
462
|
+
const ids = this.typeIndex.get(type);
|
|
463
|
+
if (!ids) return [];
|
|
464
|
+
|
|
465
|
+
return [...ids].map(id => this.get(id)).filter(Boolean);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Touch ID for LRU
|
|
470
|
+
*/
|
|
471
|
+
touch(id) {
|
|
472
|
+
const idx = this.accessOrder.indexOf(id);
|
|
473
|
+
if (idx !== -1) {
|
|
474
|
+
this.accessOrder.splice(idx, 1);
|
|
475
|
+
}
|
|
476
|
+
this.accessOrder.push(id);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Evict oldest entries if over capacity
|
|
481
|
+
*/
|
|
482
|
+
evict() {
|
|
483
|
+
while (this.cache.size > this.maxSize && this.accessOrder.length > 0) {
|
|
484
|
+
const oldId = this.accessOrder.shift();
|
|
485
|
+
const beacon = this.cache.get(oldId);
|
|
486
|
+
|
|
487
|
+
if (beacon) {
|
|
488
|
+
// Remove from indices
|
|
489
|
+
if (beacon.authorId && this.userIndex.has(beacon.authorId)) {
|
|
490
|
+
this.userIndex.get(beacon.authorId).delete(oldId);
|
|
491
|
+
}
|
|
492
|
+
if (this.typeIndex.has(beacon.type)) {
|
|
493
|
+
this.typeIndex.get(beacon.type).delete(oldId);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
this.cache.delete(oldId);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Clear all cached beacons
|
|
503
|
+
*/
|
|
504
|
+
clear() {
|
|
505
|
+
this.cache.clear();
|
|
506
|
+
this.userIndex.clear();
|
|
507
|
+
this.typeIndex.clear();
|
|
508
|
+
this.accessOrder = [];
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Get cache stats
|
|
513
|
+
*/
|
|
514
|
+
stats() {
|
|
515
|
+
return {
|
|
516
|
+
size: this.cache.size,
|
|
517
|
+
maxSize: this.maxSize,
|
|
518
|
+
userCount: this.userIndex.size,
|
|
519
|
+
typeCount: this.typeIndex.size
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Chinese Remainder Theorem Reconstructor
|
|
526
|
+
*
|
|
527
|
+
* Uses CRT to reconstruct original data from prime coefficients.
|
|
528
|
+
* F(x) = Σ(i=0 to n) c_i * p_i^k mod M
|
|
529
|
+
* R(F) = CRT(F, P) → D
|
|
530
|
+
*/
|
|
531
|
+
class CRTReconstructor {
|
|
532
|
+
/**
|
|
533
|
+
* Extended Euclidean Algorithm
|
|
534
|
+
* Returns [gcd, x, y] such that ax + by = gcd(a, b)
|
|
535
|
+
*/
|
|
536
|
+
static extendedGcd(a, b) {
|
|
537
|
+
if (b === 0n) {
|
|
538
|
+
return [a, 1n, 0n];
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const [g, x, y] = CRTReconstructor.extendedGcd(b, a % b);
|
|
542
|
+
return [g, y, x - (a / b) * y];
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Modular inverse: a^(-1) mod m
|
|
547
|
+
*/
|
|
548
|
+
static modInverse(a, m) {
|
|
549
|
+
const [g, x] = CRTReconstructor.extendedGcd(a % m, m);
|
|
550
|
+
|
|
551
|
+
if (g !== 1n) {
|
|
552
|
+
throw new Error(`No modular inverse exists for ${a} mod ${m}`);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return ((x % m) + m) % m;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Reconstruct using CRT
|
|
560
|
+
*
|
|
561
|
+
* Given remainders r_i for moduli m_i, find x such that:
|
|
562
|
+
* x ≡ r_1 (mod m_1)
|
|
563
|
+
* x ≡ r_2 (mod m_2)
|
|
564
|
+
* ...
|
|
565
|
+
*
|
|
566
|
+
* @param {Array<[bigint, bigint]>} congruences - Array of [remainder, modulus] pairs
|
|
567
|
+
* @returns {bigint} Reconstructed value
|
|
568
|
+
*/
|
|
569
|
+
static reconstruct(congruences) {
|
|
570
|
+
if (congruences.length === 0) return 0n;
|
|
571
|
+
|
|
572
|
+
// Compute product of all moduli
|
|
573
|
+
const M = congruences.reduce((prod, [, m]) => prod * m, 1n);
|
|
574
|
+
|
|
575
|
+
let result = 0n;
|
|
576
|
+
|
|
577
|
+
for (const [r, m] of congruences) {
|
|
578
|
+
const Mi = M / m;
|
|
579
|
+
const yi = CRTReconstructor.modInverse(Mi, m);
|
|
580
|
+
result = (result + r * Mi * yi) % M;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return result;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Reconstruct data from fragment coefficients
|
|
588
|
+
*
|
|
589
|
+
* @param {ResonantFragment} fragment - Source fragment
|
|
590
|
+
* @param {number} length - Expected output length
|
|
591
|
+
* @returns {Buffer} Reconstructed data
|
|
592
|
+
*/
|
|
593
|
+
static fromFragment(fragment, length = 256) {
|
|
594
|
+
// Build congruence system from coefficients
|
|
595
|
+
const congruences = [];
|
|
596
|
+
|
|
597
|
+
for (const [p, coeff] of fragment.coeffs) {
|
|
598
|
+
congruences.push([BigInt(coeff), BigInt(p)]);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (congruences.length === 0) {
|
|
602
|
+
return Buffer.alloc(0);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// Use CRT to reconstruct combined value
|
|
606
|
+
const reconstructed = CRTReconstructor.reconstruct(congruences);
|
|
607
|
+
|
|
608
|
+
// Convert to bytes
|
|
609
|
+
const hexStr = reconstructed.toString(16).padStart(length * 2, '0');
|
|
610
|
+
const buffer = Buffer.from(hexStr.slice(-length * 2), 'hex');
|
|
611
|
+
|
|
612
|
+
return buffer;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Data Summoner
|
|
618
|
+
*
|
|
619
|
+
* Orchestrates the summoning process:
|
|
620
|
+
* 1. Parse beacon to get prime indices
|
|
621
|
+
* 2. Query for matching fragments
|
|
622
|
+
* 3. Use CRT to reconstruct data
|
|
623
|
+
* 4. Verify integrity with fingerprint
|
|
624
|
+
*/
|
|
625
|
+
class DataSummoner {
|
|
626
|
+
constructor(options = {}) {
|
|
627
|
+
this.fragmentStore = options.fragmentStore || new Map();
|
|
628
|
+
this.beaconCache = options.beaconCache || new BeaconCache();
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Store a fragment and create beacon
|
|
633
|
+
* @param {Buffer|string} data - Data to store
|
|
634
|
+
* @param {Object} options - Storage options
|
|
635
|
+
*/
|
|
636
|
+
store(data, options = {}) {
|
|
637
|
+
// Create fragment from data
|
|
638
|
+
const fragment = ResonantFragment.fromData(data);
|
|
639
|
+
|
|
640
|
+
// Store fragment
|
|
641
|
+
const fragmentId = `frag_${Date.now()}_${crypto.randomBytes(4).toString('hex')}`;
|
|
642
|
+
this.fragmentStore.set(fragmentId, fragment);
|
|
643
|
+
|
|
644
|
+
// Create beacon
|
|
645
|
+
const beacon = Beacon.fromFragment(fragment, {
|
|
646
|
+
authorId: options.authorId,
|
|
647
|
+
metadata: {
|
|
648
|
+
...options.metadata,
|
|
649
|
+
fragmentId,
|
|
650
|
+
originalLength: Buffer.isBuffer(data) ? data.length : Buffer.from(data).length
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
// Cache beacon
|
|
655
|
+
this.beaconCache.set(beacon);
|
|
656
|
+
|
|
657
|
+
return { beacon, fragment, fragmentId };
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Summon data from beacon
|
|
662
|
+
* @param {Beacon|string} beaconOrId - Beacon or beacon ID
|
|
663
|
+
*/
|
|
664
|
+
summon(beaconOrId) {
|
|
665
|
+
// Resolve beacon
|
|
666
|
+
let beacon;
|
|
667
|
+
if (typeof beaconOrId === 'string') {
|
|
668
|
+
beacon = this.beaconCache.get(beaconOrId);
|
|
669
|
+
if (!beacon) {
|
|
670
|
+
throw new Error(`Beacon not found: ${beaconOrId}`);
|
|
671
|
+
}
|
|
672
|
+
} else {
|
|
673
|
+
beacon = beaconOrId;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// Get fragment
|
|
677
|
+
const fragmentId = beacon.metadata?.fragmentId;
|
|
678
|
+
if (!fragmentId) {
|
|
679
|
+
throw new Error('Beacon has no fragmentId');
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const fragment = this.fragmentStore.get(fragmentId);
|
|
683
|
+
if (!fragment) {
|
|
684
|
+
throw new Error(`Fragment not found: ${fragmentId}`);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Reconstruct data
|
|
688
|
+
const length = beacon.metadata?.originalLength || 256;
|
|
689
|
+
const data = CRTReconstructor.fromFragment(fragment, length);
|
|
690
|
+
|
|
691
|
+
// Verify integrity
|
|
692
|
+
if (beacon.fingerprint && !beacon.verify(data)) {
|
|
693
|
+
return {
|
|
694
|
+
success: false,
|
|
695
|
+
error: 'Fingerprint verification failed',
|
|
696
|
+
data: null
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
return {
|
|
701
|
+
success: true,
|
|
702
|
+
data,
|
|
703
|
+
fragment,
|
|
704
|
+
beacon
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Find fragments matching a query state
|
|
710
|
+
* @param {PrimeState} queryState - Query state
|
|
711
|
+
* @param {number} threshold - Minimum resonance
|
|
712
|
+
*/
|
|
713
|
+
findSimilar(queryState, threshold = 0.5) {
|
|
714
|
+
const results = [];
|
|
715
|
+
|
|
716
|
+
for (const [id, fragment] of this.fragmentStore) {
|
|
717
|
+
const fragState = fragment.toPrimeState();
|
|
718
|
+
const resonance = queryState.coherence(fragState);
|
|
719
|
+
|
|
720
|
+
if (resonance >= threshold) {
|
|
721
|
+
results.push({ id, fragment, resonance });
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
return results.sort((a, b) => b.resonance - a.resonance);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
module.exports = {
|
|
730
|
+
ResonantFragment,
|
|
731
|
+
Beacon,
|
|
732
|
+
BeaconCache,
|
|
733
|
+
CRTReconstructor,
|
|
734
|
+
DataSummoner
|
|
735
|
+
};
|