zkjson 0.3.1 → 0.4.0

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/collection.js CHANGED
@@ -14,8 +14,8 @@ class Collection {
14
14
  size_json: this.size_json,
15
15
  })
16
16
  }
17
- async getInputs({ id, json, path, val }) {
18
- const doc_inputs = await this.doc.getInputs({ json, path, val })
17
+ async getInputs({ id, json, path, val, query }) {
18
+ const doc_inputs = await this.doc.getInputs({ json, path, val, query })
19
19
  const res = await this.get(id)
20
20
  let siblings = res.siblings
21
21
  for (let i = 0; i < siblings.length; i++)
package/db.js CHANGED
@@ -69,13 +69,14 @@ class DB {
69
69
  return this._getVal(j, p.split("."))
70
70
  }
71
71
 
72
- async genProof({ json, col_id, path, id }) {
72
+ async genProof({ json, col_id, path, id, query }) {
73
73
  const inputs = await this.getInputs({
74
74
  id,
75
75
  col_id,
76
76
  json,
77
77
  path,
78
78
  val: this.getVal(json, path),
79
+ query,
79
80
  })
80
81
  const { proof, publicSignals } = await snarkjs.groth16.fullProve(
81
82
  inputs,
@@ -254,7 +255,7 @@ class DB {
254
255
  }
255
256
  }
256
257
 
257
- async getInputs({ id, col_id, json, path, val }) {
258
+ async getInputs({ id, col_id, json, path, val, query }) {
258
259
  const col_root = this.tree.F.toObject(this.tree.root).toString()
259
260
  const col_res = await this.getCol(col_id)
260
261
 
@@ -265,7 +266,7 @@ class DB {
265
266
  col_siblings = col_siblings.map(s => s.toString())
266
267
  const col_key = col_id
267
268
  const col = this.getColTree(col_id)
268
- const col_inputs = await col.getInputs({ id, json, path, val })
269
+ const col_inputs = await col.getInputs({ id, json, path, val, query })
269
270
  return {
270
271
  path: col_inputs.path,
271
272
  val: col_inputs.val,
package/doc.js CHANGED
@@ -46,8 +46,8 @@ module.exports = class Doc {
46
46
  if (p === "") return j
47
47
  return this._getVal(j, p.split("."))
48
48
  }
49
- async genProof(json, path) {
50
- const inputs = await this.getInputs(json, path)
49
+ async genProof({ json, path, query }) {
50
+ const inputs = await this.getInputs({ json, path, query })
51
51
  const { proof, publicSignals } = await snarkjs.groth16.fullProve(
52
52
  inputs,
53
53
  this.wasm,
package/encoder-v2.js ADDED
@@ -0,0 +1,1221 @@
1
+ const {
2
+ clone,
3
+ uniq,
4
+ sortBy,
5
+ map,
6
+ concat,
7
+ compose,
8
+ is,
9
+ descend,
10
+ ascend,
11
+ sortWith,
12
+ prop,
13
+ equals,
14
+ append,
15
+ isNil,
16
+ includes,
17
+ splitEvery,
18
+ flatten,
19
+ } = require("ramda")
20
+ const ops = {
21
+ $eq: 10,
22
+ $ne: 11,
23
+ $gt: 12,
24
+ $gte: 13,
25
+ $lt: 14,
26
+ $lte: 15,
27
+ $in: 16,
28
+ $nin: 17,
29
+ $contains: 18,
30
+ $contains_any: 19,
31
+ $contains_all: 20,
32
+ $contains_none: 21,
33
+ }
34
+ const opMap = {}
35
+ for (let k in ops) opMap[ops[k]] = k
36
+
37
+ const base64Map = {
38
+ A: "00",
39
+ B: "01",
40
+ C: "02",
41
+ D: "03",
42
+ E: "04",
43
+ F: "05",
44
+ G: "06",
45
+ H: "07",
46
+ I: "08",
47
+ J: "09",
48
+ K: "10",
49
+ L: "11",
50
+ M: "12",
51
+ N: "13",
52
+ O: "14",
53
+ P: "15",
54
+ Q: "16",
55
+ R: "17",
56
+ S: "18",
57
+ T: "19",
58
+ U: "20",
59
+ V: "21",
60
+ W: "22",
61
+ X: "23",
62
+ Y: "24",
63
+ Z: "25",
64
+ a: "26",
65
+ b: "27",
66
+ c: "28",
67
+ d: "29",
68
+ e: "30",
69
+ f: "31",
70
+ g: "32",
71
+ h: "33",
72
+ i: "34",
73
+ j: "35",
74
+ k: "36",
75
+ l: "37",
76
+ m: "38",
77
+ n: "39",
78
+ o: "40",
79
+ p: "41",
80
+ q: "42",
81
+ r: "43",
82
+ s: "44",
83
+ t: "45",
84
+ u: "46",
85
+ v: "47",
86
+ w: "48",
87
+ x: "49",
88
+ y: "50",
89
+ z: "51",
90
+ 0: "52",
91
+ 1: "53",
92
+ 2: "54",
93
+ 3: "55",
94
+ 4: "56",
95
+ 5: "57",
96
+ 6: "58",
97
+ 7: "59",
98
+ 8: "60",
99
+ 9: "61",
100
+ "-": "62",
101
+ _: "63",
102
+ }
103
+
104
+ let strMap = {}
105
+ for (const k in base64Map) strMap[base64Map[k]] = k
106
+
107
+ function pad(arr, max = 0) {
108
+ arr = arr.map(n => n.toString())
109
+ for (let i = arr.length; i < max; i++) {
110
+ arr.push("0")
111
+ }
112
+ return arr
113
+ }
114
+
115
+ function encodePath(path) {
116
+ const parts = []
117
+ let str = ""
118
+ let num = 0
119
+ for (const s of path) {
120
+ if (num == 2 && !(s == "." || s == "[")) throw Error()
121
+ if (s == ".") {
122
+ if (num == 2) {
123
+ num = 0
124
+ } else {
125
+ parts.push(str)
126
+ str = ""
127
+ }
128
+ } else if (s == "[") {
129
+ if (num != 2) {
130
+ if (str != "" || parts.length > 0) parts.push(str)
131
+ str = ""
132
+ }
133
+ num = 1
134
+ } else if (s == "]") {
135
+ if (num != 1) throw Error()
136
+ num = 2
137
+ if (str == "" || Number.isNaN(+str)) throw Error()
138
+ parts.push(+str)
139
+ str = ""
140
+ } else {
141
+ str += s
142
+ }
143
+ }
144
+ if (str != "") parts.push(str)
145
+ if (parts.length == 0) parts.push("")
146
+ let encoded = [parts.length]
147
+ for (const p of parts) {
148
+ if (typeof p == "number") {
149
+ encoded = encoded.concat([0, 0, p])
150
+ } else {
151
+ let plen = [p.length]
152
+ if (p.length == 0) plen.push(1)
153
+ encoded = encoded.concat([
154
+ ...plen,
155
+ ...p.split("").map(c => c.charCodeAt(0)),
156
+ ])
157
+ }
158
+ }
159
+ return encoded
160
+ }
161
+
162
+ function decodePath(path) {
163
+ let str = ""
164
+ let p = []
165
+ let len = path.shift()
166
+ while (path.length > 0) {
167
+ const type = path.shift()
168
+ let val = null
169
+ if (type == 0) {
170
+ const type2 = path.shift()
171
+ if (type2 == 0) {
172
+ val = [type2, path.shift()]
173
+ } else {
174
+ val = [type2]
175
+ }
176
+ } else {
177
+ val = []
178
+ for (let i = 0; i < type; i++) {
179
+ val.push(path.shift())
180
+ }
181
+ }
182
+ p.push([type, ...val])
183
+ }
184
+ let i = 0
185
+ for (let s of p) {
186
+ if (s[0] == 0 && s[1] == 0) str += `[${s[2]}]`
187
+ else if (s[0] == 0 && s[1] == 1) {
188
+ if (str != "") str += "."
189
+ } else {
190
+ str += `${i == 0 ? "" : "."}${s
191
+ .slice(1)
192
+ .map(c => String.fromCharCode(Number(c)))
193
+ .join("")}`
194
+ }
195
+ i++
196
+ }
197
+ return str
198
+ }
199
+
200
+ function flattenPath(path) {
201
+ let p = [path.length]
202
+ for (const v of path) p = p.concat(v)
203
+ return p
204
+ }
205
+
206
+ function _encode(v, path = []) {
207
+ let vals = []
208
+ if (typeof v == "number") vals.push([path, encodeVal(v)])
209
+ else if (typeof v == "boolean") vals.push([path, encodeVal(v)])
210
+ else if (v == null) vals.push([path, encodeVal(v)])
211
+ else if (typeof v == "string") vals.push([path, encodeVal(v)])
212
+ else if (Array.isArray(v)) {
213
+ let i = 0
214
+ for (const v2 of v) {
215
+ for (const v3 of _encode(v2, [...path, i])) vals.push(v3)
216
+ i++
217
+ }
218
+ } else if (typeof v == "object") {
219
+ for (const k in v) for (let v4 of _encode(v[k], [...path, k])) vals.push(v4)
220
+ }
221
+ return vals
222
+ }
223
+
224
+ const filterDic = keys => keys.filter(entry => entry.count > 1)
225
+
226
+ function countKeys(keys) {
227
+ let keys2 = []
228
+ for (let v of keys) {
229
+ let i = 0
230
+ for (let v2 of v) {
231
+ const _key = v.slice(0, i + 1)
232
+ let exists = false
233
+ for (let v3 of keys2) {
234
+ if (equals(_key, v3.key)) {
235
+ v3.count += 1
236
+ exists = true
237
+ }
238
+ }
239
+ if (!exists) keys2.push({ key: _key, count: 1 })
240
+ i++
241
+ }
242
+ }
243
+ return keys2
244
+ }
245
+
246
+ function sortKeys(keys) {
247
+ return keys.sort((a, b) => {
248
+ if (b.count !== a.count) return b.count - a.count
249
+ for (let i = 0; i < Math.min(a.key.length, b.key.length); i++) {
250
+ const aVal = a.key[i]
251
+ const bVal = b.key[i]
252
+ if (typeof aVal === "number" && typeof bVal === "string") return -1
253
+ if (typeof aVal === "string" && typeof bVal === "number") return 1
254
+ if (aVal < bVal) return -1
255
+ if (aVal > bVal) return 1
256
+ }
257
+
258
+ return a.key.length - b.key.length
259
+ })
260
+ }
261
+
262
+ function buildDic(data) {
263
+ // --- Step 1. (Optional) Save original input order if needed.
264
+ data.forEach((entry, idx) => (entry._origIdx = idx))
265
+
266
+ // --- Step 2. Sort the data in "dictionary order."
267
+ // Primary: by key array length (shorter arrays come first).
268
+ // Secondary: for keys of equal length, by the total character length (ascending)
269
+ // so that, for example, ["jane"] (4 chars) comes before ["alice"] (5 chars).
270
+ // Tertiary: if still equal, compare element-by-element using natural order.
271
+ data.sort((a, b) => {
272
+ const keyA = a.key
273
+ const keyB = b.key
274
+
275
+ // Primary: Compare array lengths.
276
+ if (keyA.length !== keyB.length) return keyA.length - keyB.length
277
+
278
+ // Secondary: Compare total character lengths (ascending).
279
+ const totalA = keyA.reduce((acc, x) => acc + x.toString().length, 0)
280
+ const totalB = keyB.reduce((acc, x) => acc + x.toString().length, 0)
281
+ if (totalA !== totalB) return totalA - totalB
282
+ // Tertiary: Compare element-by-element using natural order.
283
+ for (let i = 0; i < keyA.length; i++) {
284
+ const elA = keyA[i]
285
+ const elB = keyB[i]
286
+
287
+ if (typeof elA === typeof elB) {
288
+ if (typeof elA === "number") {
289
+ if (elA !== elB) return elA - elB
290
+ } else if (typeof elA === "string") {
291
+ const cmp = elA.localeCompare(elB, undefined, { numeric: true })
292
+ if (cmp !== 0) return cmp
293
+ } else {
294
+ // Fallback: compare string representations.
295
+ const cmp = elA
296
+ .toString()
297
+ .localeCompare(elB.toString(), undefined, { numeric: true })
298
+ if (cmp !== 0) return cmp
299
+ }
300
+ } else {
301
+ // If types differ, compare string representations.
302
+ const cmp = elA
303
+ .toString()
304
+ .localeCompare(elB.toString(), undefined, { numeric: true })
305
+ if (cmp !== 0) return cmp
306
+ }
307
+ }
308
+
309
+ return 0
310
+ })
311
+
312
+ // --- Step 3. Build the dictionary.
313
+ // Each dictionary entry will be stored as an object with:
314
+ // - original: the original key (an array)
315
+ // - compressed: the computed compressed representation.
316
+ const dict = []
317
+
318
+ // Helper: For a given string, look for a previously defined simple key (an array of length 1).
319
+ function getPointerIndex(str) {
320
+ for (let i = 0; i < dict.length; i++) {
321
+ if (dict[i].original.length === 1 && dict[i].original[0] === str) return i
322
+ }
323
+ return -1
324
+ }
325
+
326
+ // Helper: Element-by-element compression.
327
+ // For each element in a composite key, if it is a string that already exists as a simple key,
328
+ // replace one or more consecutive occurrences with a pointer.
329
+ // A single occurrence becomes [dictIndex]; a group becomes [dictIndex, 0].
330
+ function compressElementByElement(key) {
331
+ const rep = []
332
+ let i = 0
333
+ while (i < key.length) {
334
+ const el = key[i]
335
+ if (typeof el === "string") {
336
+ const ptrIndex = getPointerIndex(el)
337
+ if (ptrIndex !== -1) {
338
+ let j = i
339
+ while (j < key.length && key[j] === el) {
340
+ j++
341
+ }
342
+ const groupLen = j - i
343
+ rep.push(groupLen === 1 ? [ptrIndex] : [ptrIndex, 0])
344
+ i = j
345
+ continue
346
+ }
347
+ }
348
+ rep.push(el)
349
+ i++
350
+ }
351
+ return rep
352
+ }
353
+
354
+ // Helper: Compute a "cost" for a given representation.
355
+ // Each literal (number or string) counts as 1; a pointer array counts as the number of numbers it holds.
356
+ function computeCost(rep) {
357
+ let cost = 0
358
+ for (const token of rep) cost += Array.isArray(token) ? token.length : 1
359
+ return cost
360
+ }
361
+
362
+ // Helper: Full segmentation compression.
363
+ // Try to segment the entire key as a concatenation of one or more previously defined dictionary entries.
364
+ // Uses dynamic programming over the key array.
365
+ // Returns an object { cost, seg } where seg is an array of dictionary indices.
366
+ function segmentKey(key) {
367
+ const n = key.length
368
+ const dp = Array(n + 1).fill(null)
369
+ dp[n] = { cost: 0, seg: [] }
370
+
371
+ for (let i = n - 1; i >= 0; i--) {
372
+ let best = null
373
+ // Try every dictionary entry.
374
+ for (let d = 0; d < dict.length; d++) {
375
+ const candidate = dict[d].original
376
+ const m = candidate.length
377
+ if (i + m <= n) {
378
+ let match = true
379
+ for (let k = 0; k < m; k++) {
380
+ if (key[i + k] !== candidate[k]) {
381
+ match = false
382
+ break
383
+ }
384
+ }
385
+ if (match && dp[i + m] !== null) {
386
+ const candidateCost = 1 + dp[i + m].cost // cost 1 for using this pointer.
387
+ if (best === null || candidateCost < best.cost) {
388
+ best = { cost: candidateCost, seg: [d].concat(dp[i + m].seg) }
389
+ }
390
+ }
391
+ }
392
+ }
393
+ dp[i] = best
394
+ }
395
+ return dp[0]
396
+ }
397
+
398
+ // Process each entry (in the sorted, deterministic order).
399
+ for (const entry of data) {
400
+ const key = entry.key
401
+ let compressed
402
+ if (key.length === 1) {
403
+ // For simple keys, copy as-is.
404
+ compressed = key.slice()
405
+ } else {
406
+ // Try element-by-element compression.
407
+ const repA = compressElementByElement(key)
408
+ const costA = computeCost(repA)
409
+
410
+ // Also try full segmentation.
411
+ const segRes = segmentKey(key)
412
+ if (segRes !== null) {
413
+ const repB = [segRes.seg] // Represent segmentation as a pointer.
414
+ const costB = segRes.cost
415
+ compressed = costB < costA ? repB : repA
416
+ } else compressed = repA
417
+ }
418
+ dict.push({ original: key, compressed })
419
+ }
420
+
421
+ // --- Step 4. Return the dictionary and key map.
422
+ // "dictionary" is an array of compressed keys.
423
+ // "keyMap" is the array of original keys (in the same, deterministic order).
424
+ return {
425
+ dictionary: dict.map(entry => {
426
+ return entry.compressed.length === 1 && !is(Array, entry.compressed[0])
427
+ ? entry.compressed[0]
428
+ : entry.compressed
429
+ }),
430
+ keyMap: dict.map(entry => entry.original),
431
+ }
432
+ }
433
+
434
+ function buildDic(data) {
435
+ // --- Step 1. (Optional) Save original input order if needed.
436
+ data.forEach((entry, idx) => (entry._origIdx = idx))
437
+
438
+ // --- Step 2. Sort the data in "dictionary order."
439
+ // Primary: by key array length (shorter arrays come first).
440
+ // Secondary: for keys of equal length, by the total character length (ascending)
441
+ // so that, for example, ["jane"] (4 chars) comes before ["alice"] (5 chars).
442
+ // Tertiary: if still equal, compare element-by-element using natural order.
443
+ data.sort((a, b) => {
444
+ const keyA = a.key
445
+ const keyB = b.key
446
+
447
+ // Primary: Compare array lengths.
448
+ if (keyA.length !== keyB.length) return keyA.length - keyB.length
449
+
450
+ // Secondary: Compare total character lengths (ascending).
451
+ const totalA = keyA.reduce((acc, x) => acc + x.toString().length, 0)
452
+ const totalB = keyB.reduce((acc, x) => acc + x.toString().length, 0)
453
+ if (totalA !== totalB) return totalA - totalB
454
+ // Tertiary: Compare element-by-element using natural order.
455
+ for (let i = 0; i < keyA.length; i++) {
456
+ const elA = keyA[i]
457
+ const elB = keyB[i]
458
+
459
+ if (typeof elA === typeof elB) {
460
+ if (typeof elA === "number") {
461
+ if (elA !== elB) return elA - elB
462
+ } else if (typeof elA === "string") {
463
+ const cmp = elA.localeCompare(elB, undefined, { numeric: true })
464
+ if (cmp !== 0) return cmp
465
+ } else {
466
+ // Fallback: compare string representations.
467
+ const cmp = elA
468
+ .toString()
469
+ .localeCompare(elB.toString(), undefined, { numeric: true })
470
+ if (cmp !== 0) return cmp
471
+ }
472
+ } else {
473
+ // If types differ, compare string representations.
474
+ const cmp = elA
475
+ .toString()
476
+ .localeCompare(elB.toString(), undefined, { numeric: true })
477
+ if (cmp !== 0) return cmp
478
+ }
479
+ }
480
+
481
+ return 0
482
+ })
483
+
484
+ // --- Step 3. Build the dictionary.
485
+ // Each dictionary entry will be stored as an object with:
486
+ // - original: the original key (an array)
487
+ // - compressed: the computed compressed representation.
488
+ const dict = []
489
+
490
+ // Helper: For a given string, look for a previously defined simple key (an array of length 1).
491
+ function getPointerIndex(str) {
492
+ for (let i = 0; i < dict.length; i++) {
493
+ if (dict[i].original.length === 1 && dict[i].original[0] === str) return i
494
+ }
495
+ return -1
496
+ }
497
+
498
+ // Helper: Element-by-element compression.
499
+ // For each element in a composite key, if it is a string that already exists as a simple key,
500
+ // replace one or more consecutive occurrences with a pointer.
501
+ // A single occurrence becomes [dictIndex]; a group becomes [dictIndex, 0].
502
+ function compressElementByElement(key) {
503
+ const rep = []
504
+ let i = 0
505
+ while (i < key.length) {
506
+ const el = key[i]
507
+ if (typeof el === "string") {
508
+ const ptrIndex = getPointerIndex(el)
509
+ if (ptrIndex !== -1) {
510
+ let j = i
511
+ while (j < key.length && key[j] === el) {
512
+ j++
513
+ }
514
+ const groupLen = j - i
515
+ rep.push(groupLen === 1 ? [ptrIndex] : [ptrIndex, 0])
516
+ i = j
517
+ continue
518
+ }
519
+ }
520
+ rep.push(el)
521
+ i++
522
+ }
523
+ return rep
524
+ }
525
+
526
+ // Helper: Compute a "cost" for a given representation.
527
+ // Each literal (number or string) counts as 1; a pointer array counts as the number of numbers it holds.
528
+ function computeCost(rep) {
529
+ let cost = 0
530
+ for (const token of rep) cost += Array.isArray(token) ? token.length : 1
531
+ return cost
532
+ }
533
+
534
+ // Helper: Full segmentation compression.
535
+ // Try to segment the entire key as a concatenation of one or more previously defined dictionary entries.
536
+ // Uses dynamic programming over the key array.
537
+ // Returns an object { cost, seg } where seg is an array of dictionary indices.
538
+ function segmentKey(key) {
539
+ const n = key.length
540
+ const dp = Array(n + 1).fill(null)
541
+ dp[n] = { cost: 0, seg: [] }
542
+
543
+ for (let i = n - 1; i >= 0; i--) {
544
+ let best = null
545
+ // Try every dictionary entry.
546
+ for (let d = 0; d < dict.length; d++) {
547
+ const candidate = dict[d].original
548
+ const m = candidate.length
549
+ if (i + m <= n) {
550
+ let match = true
551
+ for (let k = 0; k < m; k++) {
552
+ if (key[i + k] !== candidate[k]) {
553
+ match = false
554
+ break
555
+ }
556
+ }
557
+ if (match && dp[i + m] !== null) {
558
+ const candidateCost = 1 + dp[i + m].cost // cost 1 for using this pointer.
559
+ if (best === null || candidateCost < best.cost) {
560
+ best = { cost: candidateCost, seg: [d].concat(dp[i + m].seg) }
561
+ }
562
+ }
563
+ }
564
+ }
565
+ dp[i] = best
566
+ }
567
+ return dp[0]
568
+ }
569
+
570
+ // Process each entry (in the sorted, deterministic order).
571
+ for (const entry of data) {
572
+ const key = entry.key
573
+ let compressed
574
+ if (key.length === 1) {
575
+ // For simple keys, copy as-is.
576
+ compressed = key.slice()
577
+ } else {
578
+ // Try element-by-element compression.
579
+ const repA = compressElementByElement(key)
580
+ let bestCost = computeCost(repA)
581
+ let bestRep = repA
582
+
583
+ // Also try full segmentation over the entire key.
584
+ const segRes = segmentKey(key)
585
+ if (segRes !== null) {
586
+ const repB = [segRes.seg] // Represent segmentation as a pointer.
587
+ const costB = segRes.cost
588
+ if (costB < bestCost) {
589
+ bestCost = costB
590
+ bestRep = repB
591
+ }
592
+ }
593
+
594
+ // Now try partial segmentation: try segmenting a prefix and then appending the literal remainder.
595
+ const n = key.length
596
+ for (let i = 1; i < n; i++) {
597
+ const prefixSeg = segmentKey(key.slice(0, i))
598
+ if (prefixSeg !== null) {
599
+ const literalPart = key.slice(i)
600
+ const candidateCost = prefixSeg.cost + computeCost(literalPart)
601
+ if (candidateCost < bestCost) {
602
+ bestCost = candidateCost
603
+ // Build candidate representation: pointer for the segmented prefix followed by literal remainder.
604
+ bestRep = [prefixSeg.seg].concat(literalPart)
605
+ }
606
+ }
607
+ }
608
+
609
+ compressed = bestRep
610
+ }
611
+ dict.push({ original: key, compressed })
612
+ }
613
+
614
+ // --- Step 4. Return the dictionary and key map.
615
+ // "dictionary" is an array of compressed keys.
616
+ // "keyMap" is the array of original keys (in the same, deterministic order).
617
+ return {
618
+ dictionary: dict.map(entry => {
619
+ return entry.compressed.length === 1 && !is(Array, entry.compressed[0])
620
+ ? entry.compressed[0]
621
+ : entry.compressed
622
+ }),
623
+ keyMap: dict.map(entry => entry.original),
624
+ }
625
+ }
626
+ const genDic = compose(buildDic, filterDic, sortKeys, countKeys, listKeys)
627
+
628
+ function listKeys(v, key = [], keys = []) {
629
+ if (Array.isArray(v)) {
630
+ let i = 0
631
+ for (const v2 of v) {
632
+ listKeys(v2, append(i, key), keys)
633
+ i++
634
+ }
635
+ } else if (typeof v == "object") {
636
+ for (const k in v) listKeys(v[k], append(k, key), keys)
637
+ } else {
638
+ keys.push(key)
639
+ }
640
+ return keys
641
+ }
642
+
643
+ function isPrefix(path, prefix) {
644
+ if (prefix.length > path.length) return false
645
+ for (let i = 0; i < prefix.length; i++) {
646
+ if (!equals(path[i], prefix[i])) return false
647
+ }
648
+ return true
649
+ }
650
+ function applyDicToPath(path, sortedDic) {
651
+ // Base case: if the path is empty, nothing to replace.
652
+ if (path.length === 0) return []
653
+ // Iterate over the dictionary entries in descending order.
654
+ for (const { entry, index } of sortedDic) {
655
+ if (isPrefix(path, entry)) {
656
+ // Found a match: remove the matched prefix.
657
+ const remainder = path.slice(entry.length)
658
+ // Recursively apply dictionary replacement on the remainder.
659
+ const replacedRemainder = applyDicToPath(remainder, sortedDic)
660
+ // If the remainder is completely replaced (i.e. replacedRemainder is a single dictionary reference array),
661
+ // then merge the current dictionary index with that.
662
+ if (replacedRemainder.length === 0) {
663
+ // No remainder: simply return the dictionary reference.
664
+ return [[index]]
665
+ }
666
+ if (Array.isArray(replacedRemainder[0])) {
667
+ // The first component is already a dictionary reference: merge the indices.
668
+ return [[index, ...replacedRemainder[0]]]
669
+ } else {
670
+ // Otherwise, return the dictionary reference for the prefix and then the literal remainder.
671
+ return [[index]].concat(replacedRemainder)
672
+ }
673
+ }
674
+ }
675
+ // If no dictionary entry applies, return the original literal path.
676
+ return path
677
+ }
678
+
679
+ function applyDic(arr, dic) {
680
+ // Build sorted dictionary entries in descending order by length.
681
+ const sortedDic = dic
682
+ .map((entry, index) => ({ entry, index }))
683
+ .sort((a, b) => b.entry.length - a.entry.length)
684
+ // For each pair, apply dictionary replacement to the path.
685
+ return arr.map(pair => {
686
+ const newPath = applyDicToPath(pair[0], sortedDic)
687
+ return [newPath, pair[1]]
688
+ })
689
+ }
690
+
691
+ function encodePaths(data) {
692
+ for (let v of data) {
693
+ let path = []
694
+ for (let v2 of v[0]) {
695
+ if (is(Number, v2)) path.push([0, 0, v2])
696
+ else if (is(String, v2)) {
697
+ const key = v2.split("").map(c => c.charCodeAt(0))
698
+ path.push([key.length, ...(key.length == 0 ? [1] : key)])
699
+ } else if (is(Array, v2)) {
700
+ if (v2.length === 1) path.push([0, 3, v2[0]])
701
+ else path.push([0, 4, v2.length, ...v2])
702
+ }
703
+ }
704
+ v[0] = path
705
+ }
706
+ return data
707
+ }
708
+
709
+ function mapDic(dic, len) {
710
+ let _map = []
711
+ while (dic.length > 0) {
712
+ let dlen = dic.shift()
713
+ let _elms = []
714
+ while (dlen > 0) {
715
+ let type = dic.shift()
716
+ let elms = []
717
+ if (type == 3) {
718
+ let slen = dic.shift()
719
+ elms.push(type)
720
+ for (let i = 0; i < slen; i++) elms.push(dic.shift())
721
+ _elms.push(elms)
722
+ } else if (type == 2) {
723
+ elms = concat(elms, [0, 0, dic.shift()])
724
+ _elms.push(elms)
725
+ } else if (type == 5) {
726
+ for (let v2 of _map[dic.shift()]) _elms.push(v2)
727
+ }
728
+ dlen--
729
+ }
730
+ _map.push(_elms)
731
+ if (_map.length === len) break
732
+ }
733
+ return _map
734
+ }
735
+
736
+ function encodeDic(dict) {
737
+ let enc = []
738
+ for (let v of dict) {
739
+ let len = 1
740
+ let elms = []
741
+ if (!is(String, v)) {
742
+ len = 0
743
+ for (let v2 of v) {
744
+ if (is(Array, v2)) {
745
+ len += v2.length
746
+ for (let v3 of v2) {
747
+ elms = concat(elms, [5, v3])
748
+ }
749
+ } else {
750
+ len += 1
751
+ if (is(String, v2)) {
752
+ elms.push(3)
753
+ elms.push(v2.length)
754
+ elms = concat(
755
+ elms,
756
+ v2.split("").map(c => c.charCodeAt(0)),
757
+ )
758
+ } else {
759
+ elms = concat(elms, [2, v2])
760
+ }
761
+ }
762
+ }
763
+ } else {
764
+ elms.push(3)
765
+ elms.push(v.length)
766
+ elms = concat(
767
+ elms,
768
+ v.split("").map(c => c.charCodeAt(0)),
769
+ )
770
+ }
771
+ enc = concat(enc, [len, ...elms])
772
+ }
773
+ return enc
774
+ }
775
+ function encode(json, nodic = false) {
776
+ let dic = null
777
+ let dictionary, keyMap
778
+ if (nodic !== true) {
779
+ ;({ dictionary, keyMap } = genDic(json))
780
+ if (dictionary.length > 0) dic = encodeDic(dictionary)
781
+ }
782
+ let enc = _encode(json)
783
+ if (dic) enc = applyDic(enc, keyMap)
784
+
785
+ enc = encodePaths(enc)
786
+ enc.sort((a, b) => {
787
+ const isUndefined = v => typeof v == "undefined"
788
+ const max = Math.max(a[0].length, b[0].length)
789
+ if (max > 0) {
790
+ for (let i = 0; i < max; i++) {
791
+ const exA = !isUndefined(a[0][i])
792
+ const exB = !isUndefined(b[0][i])
793
+ if (exA && !exB) return 1
794
+ if (!exA && exB) return -1
795
+ const max2 = Math.max(a[0][i].length, b[0][i].length)
796
+ if (max2 > 0) {
797
+ for (let i2 = 0; i2 < max2; i2++) {
798
+ const vA = a[0][i][i2]
799
+ const vB = b[0][i][i2]
800
+ const exA = !isUndefined(vA)
801
+ const exB = !isUndefined(vB)
802
+ if (exA && !exB) return 1
803
+ if (!exA && exB) return -1
804
+ if (vA > vB) return 1
805
+ if (vA < vB) return -1
806
+ }
807
+ }
808
+ }
809
+ }
810
+ return 0
811
+ })
812
+ const _dic = dic ? [1, 0, 2, dictionary.length, ...dic] : []
813
+ return concat(
814
+ _dic,
815
+ enc.reduce((arr, v) => arr.concat([...flattenPath(v[0]), ...v[1]]), []),
816
+ )
817
+ }
818
+
819
+ function _decode(arr) {
820
+ let vals = []
821
+ let dic = []
822
+ while (arr.length > 0) {
823
+ let plen = arr.shift()
824
+ let keys = []
825
+ let val = null
826
+ let skip = false
827
+ while (plen > 0) {
828
+ const plen2 = arr.shift()
829
+ if (plen2 == 0) {
830
+ const plen3 = arr.shift()
831
+ if (plen3 == 1) {
832
+ keys.push([plen2, plen3])
833
+ } else if (plen3 == 0) {
834
+ keys.push([plen2, plen3, arr.shift()])
835
+ } else if (plen3 == 2) {
836
+ const dict = arr.shift()
837
+ dic = mapDic(arr, dict)
838
+ skip = true
839
+ } else if (plen3 == 3) {
840
+ const _keys = dic[arr.shift()]
841
+ for (const k of _keys) keys.push(k)
842
+ } else if (plen3 == 4) {
843
+ let key = []
844
+ let plen4 = arr.shift()
845
+ for (let i2 = 0; i2 < plen4; i2++) {
846
+ const _keys = dic[arr.shift()]
847
+ for (const k of _keys) keys.push(k)
848
+ }
849
+ }
850
+ } else if (plen2 != 0) {
851
+ const plen3 = plen2
852
+ let key = []
853
+ for (let i2 = 0; i2 < plen3; i2++) key.push(arr.shift())
854
+ keys.push([plen2, ...key])
855
+ }
856
+ plen--
857
+ }
858
+ if (skip) continue
859
+ const type = arr.shift()
860
+ val = [type]
861
+ if (type == 5 || type == 6) {
862
+ val.push(arr.shift())
863
+ val.push(arr.shift())
864
+ } else if (type == 3 || type == 4) {
865
+ val.push(arr.shift())
866
+ } else if (type == 7) {
867
+ const strlen = arr.shift()
868
+ val.push(strlen)
869
+ for (let i2 = 0; i2 < strlen; i2++) val.push(arr.shift())
870
+ }
871
+ vals.push([keys, val])
872
+ }
873
+ return vals
874
+ }
875
+
876
+ // 0: null, 1: true, 2: false, 3: positive integer, 4: negative integer, 5: positive float, 6: negative float, 7: string, 8: object, 9: ref
877
+
878
+ function encodeVal(v) {
879
+ let vals = []
880
+ if (typeof v == "number" || typeof v == "bigint") {
881
+ const int = Number.isInteger(v)
882
+ let moved = 0
883
+ let num = v
884
+ while (num % 1 != 0) {
885
+ num *= 10
886
+ moved += 1
887
+ }
888
+ let type = 3
889
+ if (v >= 0) {
890
+ if (moved > 0) type = 5
891
+ } else {
892
+ if (moved > 0) type = 6
893
+ else type = 4
894
+ }
895
+ vals.push(type)
896
+ if (moved > 0) vals.push(moved)
897
+ if (v < 0) vals.push(-num)
898
+ else vals.push(num)
899
+ } else if (typeof v == "boolean") vals.push(v ? 1 : 2)
900
+ else if (v == null) vals = [0]
901
+ else if (typeof v == "string") {
902
+ vals = [7, v.length, ...v.split("").map(c => c.charCodeAt(0))]
903
+ } else vals = [8, ...encode(v)]
904
+ return vals
905
+ }
906
+
907
+ function decodeVal(arr) {
908
+ const type = arr[0]
909
+ const _val = arr[1]
910
+ let val = null
911
+ if (type == 0) {
912
+ val = null
913
+ } else if (type == 1) {
914
+ val = true
915
+ } else if (type == 2) {
916
+ val = false
917
+ } else if (type == 3) {
918
+ val = arr[1]
919
+ } else if (type == 4) {
920
+ val = arr[1] * -1
921
+ } else if (type == 5) {
922
+ val = arr[2]
923
+ for (let i = 0; i < arr[1]; i++) {
924
+ val /= 10
925
+ }
926
+ } else if (type == 6) {
927
+ val = arr[2] * -1
928
+ for (let i = 0; i < arr[1]; i++) {
929
+ val /= 10
930
+ }
931
+ } else if (type == 7) {
932
+ val = arr
933
+ .slice(2)
934
+ .map(c => String.fromCharCode(Number(c)))
935
+ .join("")
936
+ } else if (type == 8) {
937
+ val = decode(arr.slice(1))
938
+ }
939
+ return val
940
+ }
941
+
942
+ function decode(arr) {
943
+ const decoded = _decode(arr)
944
+ let json =
945
+ decoded[0]?.[0]?.[0]?.[0] == 0 && decoded[0]?.[0]?.[0]?.[1] == 0 ? [] : {}
946
+ for (const v of decoded) {
947
+ const keys = v[0].map(v2 => {
948
+ if (v2[0] == 0) {
949
+ if (v2[1] == 1) return ""
950
+ return v2[2]
951
+ } else {
952
+ return v2
953
+ .slice(1)
954
+ .map(c => String.fromCharCode(Number(c)))
955
+ .join("")
956
+ }
957
+ })
958
+ if (keys.length == 0) {
959
+ json = decodeVal(v[1])
960
+ } else {
961
+ let obj = json
962
+ let i = 0
963
+ for (const k of keys) {
964
+ if (typeof k == "number") {
965
+ if (typeof keys[i + 1] == "undefined") {
966
+ obj[k] = decodeVal(v[1])
967
+ } else {
968
+ if (typeof obj[k] == "undefined") {
969
+ if (typeof keys[i + 1] == "string") {
970
+ obj[k] = {}
971
+ } else {
972
+ obj[k] = []
973
+ }
974
+ }
975
+ }
976
+ } else {
977
+ if (typeof obj[k] == "undefined") {
978
+ if (typeof keys[i + 1] == "undefined") {
979
+ obj[k] = decodeVal(v[1])
980
+ } else if (typeof keys[i + 1] == "string") {
981
+ obj[k] = {}
982
+ } else {
983
+ obj[k] = []
984
+ }
985
+ }
986
+ }
987
+ obj = obj[k]
988
+ i++
989
+ }
990
+ }
991
+ }
992
+ return json
993
+ }
994
+
995
+ const toIndex = str => {
996
+ return (
997
+ "1" +
998
+ str
999
+ .split("")
1000
+ .map(s => base64Map[s])
1001
+ .join("")
1002
+ )
1003
+ }
1004
+
1005
+ const fromIndex = id => {
1006
+ let _id = id.toString().split("")
1007
+ _id.shift()
1008
+ return splitEvery(2, _id)
1009
+ .map(s => {
1010
+ return strMap[s.join("")]
1011
+ })
1012
+ .join("")
1013
+ }
1014
+
1015
+ function toSignal(arr, uint_len = 75) {
1016
+ const _arr = flatten(
1017
+ arr.map(n => {
1018
+ let str = splitEvery(8, n.toString().split(""))
1019
+ let i = 0
1020
+ str = str.map(s => {
1021
+ const len = i == str.length - 1 ? s.length : 9
1022
+ i++
1023
+ return len.toString() + s.join("")
1024
+ })
1025
+ return str
1026
+ }),
1027
+ )
1028
+ let _arr2 = []
1029
+ let one = 0
1030
+ let i = 0
1031
+ let start = null
1032
+ if (!uint_len) uint_len = _arr * 100
1033
+ for (let v of _arr) {
1034
+ _arr2.push(v)
1035
+ if (v.length - 1 == 1) {
1036
+ if (start == null) start = i
1037
+ one += v.length - 1
1038
+ if (one == 9) {
1039
+ _arr2[start] = `0${one}${_arr2[start][1]}`
1040
+ for (let i2 = start + 1; i2 <= i; i2++) _arr2[i2] = `${_arr2[i2][1]}`
1041
+ one = 0
1042
+ start = null
1043
+ }
1044
+ } else {
1045
+ if (one > 2) {
1046
+ _arr2[start] = `0${one}${_arr2[start][1]}`
1047
+ for (let i2 = start + 1; i2 < i; i2++) _arr2[i2] = `${_arr2[i2][1]}`
1048
+ }
1049
+ one = 0
1050
+ start = null
1051
+ }
1052
+ i++
1053
+ }
1054
+ if (one > 2) {
1055
+ _arr2[start] = `0${one}${_arr2[start][1]}`
1056
+ for (let i2 = start + 1; i2 <= i - 1; i2++) _arr2[i2] = `${_arr2[i2][1]}`
1057
+ }
1058
+ let _arr3 = []
1059
+ let chain = null
1060
+ let cur = 0
1061
+ let num = ""
1062
+ for (let v of _arr2) {
1063
+ if (chain == null && +v[0] == 0) {
1064
+ chain = +v[1]
1065
+ cur = 1
1066
+ num = v
1067
+ } else if (chain != null) {
1068
+ num += v
1069
+ cur++
1070
+ if (chain == cur) {
1071
+ _arr3.push(num)
1072
+ chain = null
1073
+ num = ""
1074
+ cur = 0
1075
+ }
1076
+ } else {
1077
+ _arr3.push(v)
1078
+ }
1079
+ }
1080
+ if (chain != null) _arr3.push(num)
1081
+ let arrs2 = []
1082
+ let len2 = 0
1083
+ let str2 = ""
1084
+ for (let v of _arr3) {
1085
+ if (len2 + v.length > uint_len) {
1086
+ arrs2.push("1" + str2)
1087
+ if (+v[0] == 0) {
1088
+ let len3 = uint_len - len2
1089
+ if (len3 == 2 || len3 == 3) {
1090
+ arrs2[arrs2.length - 1] += `1${v[2]}`
1091
+ let new_len = +v[1] - 1
1092
+ if (new_len == 2) {
1093
+ v = `1${v[3]}1${v[4]}`
1094
+ } else {
1095
+ v = `0${new_len}${v.slice(3)}`
1096
+ }
1097
+ } else if (len3 > 3) {
1098
+ let new_len = +v[1] - 2
1099
+ let old_len = 2
1100
+ if (len3 == 4) {
1101
+ arrs2[arrs2.length - 1] += `1${v[2]}1${v[3]}`
1102
+ } else {
1103
+ old_len = len3 - 2
1104
+ new_len = +v[1] - old_len
1105
+ arrs2[arrs2.length - 1] += `0${old_len}${v.slice(2, 2 + old_len)}`
1106
+ }
1107
+ if (new_len == 1) {
1108
+ v = `1${v[old_len + 2]}`
1109
+ } else if (new_len == 2) {
1110
+ v = `1${v[old_len + 2]}1${v[old_len + 3]}`
1111
+ } else {
1112
+ v = `0${new_len}${v.slice(old_len + 2)}`
1113
+ }
1114
+ }
1115
+ }
1116
+ len2 = 0
1117
+ str2 = ""
1118
+ }
1119
+ len2 += v.length
1120
+ str2 += v
1121
+ }
1122
+ if (str2 != "") arrs2.push("1" + str2)
1123
+ return arrs2
1124
+ }
1125
+
1126
+ function fromSignal(arr) {
1127
+ let _arr = []
1128
+ let prev = ""
1129
+ for (let s of arr) {
1130
+ s = s.slice(1)
1131
+ let str = s.split("")
1132
+ while (str.length > 0) {
1133
+ const len = +str.shift()
1134
+ if (len == 0) {
1135
+ const len2 = +str.shift()
1136
+ for (let i2 = 0; i2 < len2; i2++) {
1137
+ _arr.push(+str[i2])
1138
+ }
1139
+ str = str.slice(len2)
1140
+ } else if (len == 9) {
1141
+ prev += str.slice(0, 8).join("")
1142
+ str = str.slice(8)
1143
+ } else {
1144
+ const nums = str.slice(0, len).join("")
1145
+ str = str.slice(len)
1146
+ _arr.push(+(prev + nums))
1147
+ prev = ""
1148
+ }
1149
+ }
1150
+ }
1151
+ return _arr
1152
+ }
1153
+
1154
+ const path = p => toSignal(encodePath(p))
1155
+ const val = v => toSignal(encodeVal(v))
1156
+ const query = v => toSignal(encodeQuery(v))
1157
+
1158
+ function encodeQuery(v) {
1159
+ if (!Array.isArray(v)) throw Error("query must be an array")
1160
+ const op = v[0]
1161
+ if (isNil(ops[op])) throw Error(`query not supported: ${op}`)
1162
+ return [ops[op], ...encodeVal(v[1])]
1163
+ }
1164
+
1165
+ function decodeQuery(v) {
1166
+ const op = opMap[v[0]]
1167
+ if (isNil(op)) throw Error("op doens't exist")
1168
+ return [op, decodeVal(v.slice(1))]
1169
+ }
1170
+
1171
+ function toUint8(sig) {
1172
+ let num = BigInt(sig)
1173
+ let byteArray = []
1174
+ while (num > 0) {
1175
+ byteArray.push(Number(num % 256n))
1176
+ num /= 256n
1177
+ }
1178
+ return new Uint8Array(byteArray.reverse())
1179
+ }
1180
+ function compress(arr) {
1181
+ let sig = toSignal(arr, false)
1182
+ return toUint8(sig)
1183
+ }
1184
+
1185
+ function decompress(arr) {
1186
+ const str = fromUint8(arr)
1187
+ return fromSignal([str])
1188
+ }
1189
+
1190
+ function fromUint8(arr) {
1191
+ let num = 0n
1192
+ for (let byte of arr) {
1193
+ num = num * 256n + BigInt(byte)
1194
+ }
1195
+ return num.toString()
1196
+ }
1197
+
1198
+ module.exports = {
1199
+ encode,
1200
+ decode,
1201
+ encodePath,
1202
+ decodePath,
1203
+ encodeVal,
1204
+ decodeVal,
1205
+ pad,
1206
+ _encode,
1207
+ flattenPath,
1208
+ toSignal,
1209
+ fromSignal,
1210
+ toIndex,
1211
+ fromIndex,
1212
+ path,
1213
+ val,
1214
+ query,
1215
+ encodeQuery,
1216
+ decodeQuery,
1217
+ compress,
1218
+ decompress,
1219
+ toUint8,
1220
+ fromUint8,
1221
+ }
package/encoder.js CHANGED
@@ -270,7 +270,7 @@ function _decode(arr) {
270
270
  }
271
271
  } else if (plen2 != 0) {
272
272
  const plen3 = plen2
273
- const key = []
273
+ let key = []
274
274
  for (let i2 = 0; i2 < plen3; i2++) key.push(arr.shift())
275
275
  keys.push([plen2, ...key])
276
276
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zkjson",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Zero Knowledge Provable JSON",
5
5
  "main": "index.js",
6
6
  "license": "MIT",