zkjson 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
package/collection.js ADDED
@@ -0,0 +1,35 @@
1
+ const newMemEmptyTrie = require("./circomlibjs").newMemEmptyTrie
2
+ const { pad, str2val, val2str, id2str, encode, str2id } = require("./encoder")
3
+
4
+ class Collection {
5
+ constructor(size = 16) {
6
+ this.size = size
7
+ }
8
+ async init() {
9
+ this.tree = await newMemEmptyTrie()
10
+ }
11
+ async insert(_key, _val) {
12
+ const doc = encode(_val)
13
+ const id = str2id(_key)
14
+ const val = pad(val2str(doc), this.size)
15
+ return await this.tree.insert(id, val)
16
+ }
17
+ async update(_key, _val) {
18
+ const doc = encode(_val)
19
+ const id = str2id(_key)
20
+ const val = pad(val2str(doc), this.size)
21
+ return await this.tree.update(id, val)
22
+ }
23
+
24
+ async delete(_key) {
25
+ const id = str2id(_key)
26
+ return await this.tree.delete(id)
27
+ }
28
+
29
+ async get(_key) {
30
+ const id = str2id(_key)
31
+ return await this.tree.find(id)
32
+ }
33
+ }
34
+
35
+ module.exports = Collection
package/db.js ADDED
@@ -0,0 +1,70 @@
1
+ const newMemEmptyTrie = require("./circomlibjs").newMemEmptyTrie
2
+ const { str2val, val2str, id2str, encode, str2id } = require("./encoder")
3
+ const Collection = require("./collection")
4
+
5
+ class DB {
6
+ constructor(size = 16) {
7
+ this.size = size
8
+ }
9
+ async init() {
10
+ this.tree = await newMemEmptyTrie()
11
+ this.cols = {}
12
+ }
13
+ async addCollection(_key) {
14
+ const id = str2id(_key)
15
+ const col = await this.tree.find(id)
16
+ if (col.found) throw Error("collection exists")
17
+ const _col = new Collection(this.size)
18
+ await _col.init()
19
+ this.cols[_key] = _col
20
+ const root = _col.tree.F.toObject(_col.tree.root).toString()
21
+ await this.tree.insert(id, [root])
22
+ }
23
+ getColTree(col) {
24
+ const _col = this.cols[col]
25
+ if (!_col) throw Error("collection doesn't exist")
26
+ return _col
27
+ }
28
+ async insert(col, _key, _val) {
29
+ const _col = this.getColTree(col)
30
+ let update = false
31
+ let res_doc
32
+ if ((await _col.get(_key)).found) {
33
+ update = true
34
+ res_doc = await _col.update(_key, _val)
35
+ } else {
36
+ res_doc = await _col.insert(_key, _val)
37
+ }
38
+ const res_col = await this.updateDB(_col, col)
39
+ return { update, doc: res_doc, col: res_col, tree: _col.tree }
40
+ }
41
+ async updateDB(_col, col) {
42
+ const root = _col.tree.F.toObject(_col.tree.root).toString()
43
+ const colD = str2id(col)
44
+ return await this.tree.update(colD, [root])
45
+ }
46
+ async update(col, _key, _val) {
47
+ const _col = this.getColTree(col)
48
+ const res_doc = await _col.update(_key, _val)
49
+ const res_col = await this.updateDB(_col, col)
50
+ return { doc: res_doc, col: res_col, tree: _col.tree }
51
+ }
52
+
53
+ async delete(col, _key) {
54
+ const _col = this.getColTree(col)
55
+ const res_doc = await _col.delete(_key)
56
+ const res_col = await this.updateDB(_col, col)
57
+ return { doc: res_doc, col: res_col, tree: _col.tree }
58
+ }
59
+
60
+ async get(col, _key) {
61
+ const _col = this.getColTree(col)
62
+ return await _col.get(_key)
63
+ }
64
+ async getCol(_key) {
65
+ const id = str2id(_key)
66
+ return await this.tree.find(id)
67
+ }
68
+ }
69
+
70
+ module.exports = DB
package/encoder.js ADDED
@@ -0,0 +1,458 @@
1
+ const { splitEvery, flatten } = require("ramda")
2
+ const base64Map = {
3
+ A: "00",
4
+ B: "01",
5
+ C: "02",
6
+ D: "03",
7
+ E: "04",
8
+ F: "05",
9
+ G: "06",
10
+ H: "07",
11
+ I: "08",
12
+ J: "09",
13
+ K: "10",
14
+ L: "11",
15
+ M: "12",
16
+ N: "13",
17
+ O: "14",
18
+ P: "15",
19
+ Q: "16",
20
+ R: "17",
21
+ S: "18",
22
+ T: "19",
23
+ U: "20",
24
+ V: "21",
25
+ W: "22",
26
+ X: "23",
27
+ Y: "24",
28
+ Z: "25",
29
+ a: "26",
30
+ b: "27",
31
+ c: "28",
32
+ d: "29",
33
+ e: "30",
34
+ f: "31",
35
+ g: "32",
36
+ h: "33",
37
+ i: "34",
38
+ j: "35",
39
+ k: "36",
40
+ l: "37",
41
+ m: "38",
42
+ n: "39",
43
+ o: "40",
44
+ p: "41",
45
+ q: "42",
46
+ r: "43",
47
+ s: "44",
48
+ t: "45",
49
+ u: "46",
50
+ v: "47",
51
+ w: "48",
52
+ x: "49",
53
+ y: "50",
54
+ z: "51",
55
+ 0: "52",
56
+ 1: "53",
57
+ 2: "54",
58
+ 3: "55",
59
+ 4: "56",
60
+ 5: "57",
61
+ 6: "58",
62
+ 7: "59",
63
+ 8: "60",
64
+ 9: "61",
65
+ "-": "62",
66
+ _: "63",
67
+ }
68
+
69
+ let strMap = {}
70
+ for (const k in base64Map) strMap[base64Map[k]] = k
71
+
72
+ function pad(arr, max = 0) {
73
+ arr = arr.map(n => n.toString())
74
+ for (let i = arr.length; i < max; i++) {
75
+ arr.push("0")
76
+ }
77
+ return arr
78
+ }
79
+
80
+ function encodePath(path) {
81
+ const parts = []
82
+ let str = ""
83
+ let num = 0
84
+ for (const s of path) {
85
+ if (num === 2 && !(s === "." || s === "[")) throw Error()
86
+ if (s === ".") {
87
+ if (num === 2) {
88
+ num = 0
89
+ } else {
90
+ parts.push(str)
91
+ str = ""
92
+ }
93
+ } else if (s === "[") {
94
+ if (num !== 2) {
95
+ if (str !== "" || parts.length > 0) parts.push(str)
96
+ str = ""
97
+ }
98
+ num = 1
99
+ } else if (s === "]") {
100
+ if (num !== 1) throw Error()
101
+ num = 2
102
+ if (str === "" || Number.isNaN(+str)) throw Error()
103
+ parts.push(+str)
104
+ str = ""
105
+ } else {
106
+ str += s
107
+ }
108
+ }
109
+ if (str !== "") parts.push(str)
110
+ if (parts.length === 0) parts.push("")
111
+ let encoded = [parts.length]
112
+ for (const p of parts) {
113
+ if (typeof p === "number") {
114
+ encoded = encoded.concat([0, 0, p])
115
+ } else {
116
+ let plen = [p.length]
117
+ if (p.length === 0) plen.push(1)
118
+ encoded = encoded.concat([
119
+ ...plen,
120
+ ...p.split("").map(c => c.charCodeAt(0)),
121
+ ])
122
+ }
123
+ }
124
+ return encoded
125
+ }
126
+
127
+ function decodePath(path) {
128
+ let str = ""
129
+ let p = []
130
+ let len = path.shift()
131
+ while (path.length > 0) {
132
+ const type = path.shift()
133
+ let val = null
134
+ if (type === 0) {
135
+ const type2 = path.shift()
136
+ if (type2 === 0) {
137
+ val = [type2, path.shift()]
138
+ } else {
139
+ val = [type2]
140
+ }
141
+ } else {
142
+ val = []
143
+ for (let i = 0; i < type; i++) {
144
+ val.push(path.shift())
145
+ }
146
+ }
147
+ p.push([type, ...val])
148
+ }
149
+ let i = 0
150
+ for (let s of p) {
151
+ if (s[0] === 0 && s[1] === 0) {
152
+ str += `[${s[2]}]`
153
+ } else if (s[0] === 0 && s[1] === 1) {
154
+ if (str !== "") str += "."
155
+ } else {
156
+ str += `${i === 0 ? "" : "."}${s
157
+ .slice(1)
158
+ .map(c => String.fromCharCode(c))
159
+ .join("")}`
160
+ }
161
+ i++
162
+ }
163
+ return str
164
+ }
165
+
166
+ function flattenPath(path) {
167
+ let p = [path.length]
168
+ for (const v of path) {
169
+ p = p.concat(v)
170
+ }
171
+ return p
172
+ }
173
+
174
+ function _encode(v, path = []) {
175
+ let vals = []
176
+ if (typeof v === "number") {
177
+ vals.push([path, encodeVal(v)])
178
+ } else if (typeof v === "boolean") {
179
+ vals.push([path, encodeVal(v)])
180
+ } else if (v === null) {
181
+ vals.push([path, encodeVal(v)])
182
+ } else if (typeof v === "string") {
183
+ vals.push([path, encodeVal(v)])
184
+ } else if (Array.isArray(v)) {
185
+ let i = 0
186
+ for (const v2 of v) {
187
+ for (const v3 of _encode(v2, [...path, [0, 0, i]])) vals.push(v3)
188
+ i++
189
+ }
190
+ } else if (typeof v === "object") {
191
+ for (const k in v) {
192
+ const key = k.split("").map(c => c.charCodeAt(0))
193
+ for (let v4 of _encode(v[k], [
194
+ ...path,
195
+ [key.length, ...(key.length === 0 ? [1] : key)],
196
+ ])) {
197
+ vals.push(v4)
198
+ }
199
+ }
200
+ }
201
+ return vals
202
+ }
203
+
204
+ function encode(json) {
205
+ let flattened = _encode(json)
206
+
207
+ flattened.sort((a, b) => {
208
+ const isUndefined = v => typeof v === "undefined"
209
+ const max = Math.max(a[0].length, b[0].length)
210
+ if (max > 0) {
211
+ for (let i = 0; i < max; i++) {
212
+ const exA = !isUndefined(a[0][i])
213
+ const exB = !isUndefined(b[0][i])
214
+ if (exA && !exB) return 1
215
+ if (!exA && exB) return -1
216
+ const max2 = Math.max(a[0][i].length, b[0][i].length)
217
+ if (max2 > 0) {
218
+ for (let i2 = 0; i2 < max2; i2++) {
219
+ const vA = a[0][i][i2]
220
+ const vB = b[0][i][i2]
221
+ const exA = !isUndefined(vA)
222
+ const exB = !isUndefined(vB)
223
+ if (exA && !exB) return 1
224
+ if (!exA && exB) return -1
225
+ if (vA > vB) return 1
226
+ if (vA < vB) return -1
227
+ }
228
+ }
229
+ }
230
+ }
231
+ return 0
232
+ })
233
+
234
+ return flattened.reduce(
235
+ (arr, v) => arr.concat([...flattenPath(v[0]), ...v[1]]),
236
+ []
237
+ )
238
+ }
239
+
240
+ function _decode(arr) {
241
+ let vals = []
242
+ while (arr.length > 0) {
243
+ let plen = arr.shift()
244
+ let keys = []
245
+ let val = null
246
+ while (plen > 0) {
247
+ const plen2 = arr.shift()
248
+ if (plen2 === 0) {
249
+ const plen3 = arr.shift()
250
+ if (plen3 === 1) {
251
+ keys.push([plen2, plen3])
252
+ } else {
253
+ keys.push([plen2, plen3, arr.shift()])
254
+ }
255
+ } else if (plen2 !== 0) {
256
+ const plen3 = plen2
257
+ const key = []
258
+ for (let i2 = 0; i2 < plen3; i2++) key.push(arr.shift())
259
+ keys.push([plen2, ...key])
260
+ }
261
+ plen--
262
+ }
263
+ const type = arr.shift()
264
+ val = [type]
265
+ if (type === 2) {
266
+ val.push(arr.shift())
267
+ val.push(arr.shift())
268
+ val.push(arr.shift())
269
+ } else if (type === 1) {
270
+ val.push(arr.shift())
271
+ } else if (type === 3) {
272
+ const strlen = arr.shift()
273
+ val.push(strlen)
274
+ for (let i2 = 0; i2 < strlen; i2++) val.push(arr.shift())
275
+ }
276
+ vals.push([keys, val])
277
+ }
278
+ return vals
279
+ }
280
+
281
+ function encodeVal(v) {
282
+ let vals = []
283
+ if (typeof v === "number") {
284
+ const int = Number.isInteger(v)
285
+ let moved = 0
286
+ let num = v
287
+ while (num % 1 !== 0) {
288
+ num *= 10
289
+ moved += 1
290
+ }
291
+ vals = v < 0 ? [2, 0, moved, -num] : [2, 1, moved, num]
292
+ } else if (typeof v === "boolean") {
293
+ vals = [1, v ? 1 : 0]
294
+ } else if (v === null) {
295
+ vals = [0]
296
+ } else if (typeof v === "string") {
297
+ vals = [3, v.length, ...v.split("").map(c => c.charCodeAt(0))]
298
+ }
299
+ return vals
300
+ }
301
+
302
+ function decodeVal(arr) {
303
+ const type = arr[0]
304
+ const _val = arr[1]
305
+ let val = null
306
+ if (type === 0) {
307
+ val = null
308
+ } else if (type === 1) {
309
+ val = arr[1] ? true : false
310
+ } else if (type === 2) {
311
+ val = (arr[1] === 0 ? -1 : 1) * arr[3]
312
+ for (let i = 0; i < arr[2]; i++) {
313
+ val /= 10
314
+ }
315
+ } else if (type === 3) {
316
+ val = arr
317
+ .slice(2)
318
+ .map(c => String.fromCharCode(c))
319
+ .join("")
320
+ }
321
+ return val
322
+ }
323
+
324
+ function decode(arr) {
325
+ const decoded = _decode(arr)
326
+ let json =
327
+ decoded[0]?.[0]?.[0]?.[0] === 0 && decoded[0]?.[0]?.[0]?.[1] === 0 ? [] : {}
328
+ for (const v of decoded) {
329
+ const keys = v[0].map(v2 => {
330
+ if (v2[0] === 0) {
331
+ if (v2[1] === 1) return ""
332
+ return v2[2]
333
+ } else {
334
+ return v2
335
+ .slice(1)
336
+ .map(c => String.fromCharCode(c))
337
+ .join("")
338
+ }
339
+ })
340
+ if (keys.length === 0) {
341
+ json = decodeVal(v[1])
342
+ } else {
343
+ let obj = json
344
+ let i = 0
345
+ for (const k of keys) {
346
+ if (typeof k === "number") {
347
+ if (typeof keys[i + 1] === "undefined") {
348
+ obj[k] = decodeVal(v[1])
349
+ } else {
350
+ if (typeof obj[k] === "undefined") {
351
+ if (typeof keys[i + 1] === "string") {
352
+ obj[k] = {}
353
+ } else {
354
+ obj[k] = []
355
+ }
356
+ }
357
+ }
358
+ } else {
359
+ if (typeof obj[k] === "undefined") {
360
+ if (typeof keys[i + 1] === "undefined") {
361
+ obj[k] = decodeVal(v[1])
362
+ } else if (typeof keys[i + 1] === "string") {
363
+ obj[k] = {}
364
+ } else {
365
+ obj[k] = []
366
+ }
367
+ }
368
+ }
369
+ obj = obj[k]
370
+ i++
371
+ }
372
+ }
373
+ }
374
+ return json
375
+ }
376
+
377
+ const str2id = str => {
378
+ return (
379
+ "1" +
380
+ str
381
+ .split("")
382
+ .map(s => base64Map[s])
383
+ .join("")
384
+ )
385
+ }
386
+
387
+ const id2str = id => {
388
+ id.shift()
389
+ return splitEvery(2, id)
390
+ .map(s => strMap[s])
391
+ .join("")
392
+ }
393
+
394
+ function val2str(arr) {
395
+ const _arr = flatten(
396
+ arr.map(n => {
397
+ let str = splitEvery(8, n.toString().split(""))
398
+ let i = 0
399
+ str = str.map(s => {
400
+ const len = i === str.length - 1 ? s.length : 9
401
+ i++
402
+ return len.toString() + s.join("")
403
+ })
404
+ return str
405
+ })
406
+ )
407
+ let arrs = []
408
+ let len = 0
409
+ let str = ""
410
+ for (let v of _arr) {
411
+ if (len + v.length > 76) {
412
+ len = 0
413
+ arrs.push(str)
414
+ str = ""
415
+ }
416
+ len += v.length
417
+ str += v
418
+ }
419
+ if (str !== "") arrs.push(str)
420
+ return arrs
421
+ }
422
+
423
+ function str2val(arr) {
424
+ let _arr = []
425
+ let prev = ""
426
+ for (const s of arr) {
427
+ let str = s.split("")
428
+ while (str.length > 0) {
429
+ const len = +str.shift()
430
+ if (len === 9) {
431
+ prev += str.slice(0, 8).join("")
432
+ str = str.slice(8)
433
+ } else {
434
+ const nums = str.slice(0, len).join("")
435
+ str = str.slice(len)
436
+ _arr.push(+(prev + nums))
437
+ prev = ""
438
+ }
439
+ }
440
+ }
441
+ return _arr
442
+ }
443
+
444
+ module.exports = {
445
+ encode,
446
+ decode,
447
+ encodePath,
448
+ decodePath,
449
+ encodeVal,
450
+ decodeVal,
451
+ pad,
452
+ _encode,
453
+ flattenPath,
454
+ str2id,
455
+ val2str,
456
+ str2val,
457
+ id2str,
458
+ }
package/index.js ADDED
@@ -0,0 +1,5 @@
1
+ const encoder = require("./encoder")
2
+ const DB = require("./db")
3
+ const Collection = require("./collection")
4
+
5
+ module.exports = { ...encoder, DB, Collection }
package/package.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "zkjson",
3
+ "version": "0.1.0",
4
+ "description": "Zero Knowledge Provable JSON",
5
+ "main": "index.js",
6
+ "license": "MIT"
7
+ }