From c97c71de7bd6f449affbdae9d988df3c84974a51 Mon Sep 17 00:00:00 2001 From: ilya-korotya Date: Fri, 23 Aug 2024 14:10:43 +0200 Subject: [PATCH 1/6] calc depth in right way; sync json tags with golang implementation --- src/lib/merkletree/proof.ts | 13 +++++++------ tests/full.test.ts | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/lib/merkletree/proof.ts b/src/lib/merkletree/proof.ts index 59593d2..8c88b01 100644 --- a/src/lib/merkletree/proof.ts +++ b/src/lib/merkletree/proof.ts @@ -10,7 +10,7 @@ import { Bytes } from '../../types'; export interface ProofJSON { existence: boolean; siblings: string[]; - nodeAux: NodeAuxJSON | undefined; + node_aux: NodeAuxJSON | undefined; } export interface NodeAuxJSON { @@ -28,7 +28,7 @@ export class Proof { constructor(obj?: { siblings: Siblings; nodeAux: NodeAux | undefined; existence: boolean }) { this.existence = obj?.existence ?? false; - this.depth = obj?.siblings.length ?? 0; + this.depth = 0; this.nodeAux = obj?.nodeAux; const { siblings, notEmpties } = this.reduceSiblings(obj?.siblings); @@ -66,7 +66,7 @@ export class Proof { return { existence: this.existence, siblings: this.allSiblings().map((s) => s.toJSON()), - nodeAux: this.nodeAux + node_aux: this.nodeAux ? { key: this.nodeAux.key.toJSON(), value: this.nodeAux.value.toJSON() @@ -87,6 +87,7 @@ export class Proof { if (JSON.stringify(siblings[i]) !== JSON.stringify(ZERO_HASH)) { setBitBigEndian(notEmpties, i); reducedSiblings.push(sibling); + this.depth = i + 1; } } return { notEmpties, siblings: reducedSiblings }; @@ -94,10 +95,10 @@ export class Proof { public static fromJSON(obj: ProofJSON): Proof { let nodeAux: NodeAux | undefined = undefined; - if (obj.nodeAux) { + if (obj.node_aux) { nodeAux = { - key: Hash.fromString(obj.nodeAux.key), - value: Hash.fromString(obj.nodeAux.value) + key: Hash.fromString(obj.node_aux.key), + value: Hash.fromString(obj.node_aux.value) }; } const existence = obj.existence ?? false; diff --git a/tests/full.test.ts b/tests/full.test.ts index 5731f0f..5af9188 100644 --- a/tests/full.test.ts +++ b/tests/full.test.ts @@ -1183,6 +1183,29 @@ for (let index = 0; index < storages.length; index++) { expect(cvp.value.string()).to.be.equal('22'); expect(cvp.fnc).to.be.equal(0); }); + it('calcualte depth for mtp', async () => { + const storage = getTreeStorage('calculatedepth'); + const mt = new Merkletree(storage, true, 40); + + await mt.add(BigInt('1'), BigInt('2')); + await mt.add(BigInt('3'), BigInt('8')); + await mt.add(BigInt('7'), BigInt('8')); + await mt.add(BigInt('9'), BigInt('8')); + + const { proof }: { proof: Proof } = await mt.generateProof(BigInt('11'), await mt.root()); + + const given = `{ "existence": false, "siblings": [ "0", "12166698708103333637493481507263348370172773813051235807348785759284762677336", "7750564177398573185975752951631372712868228752107043582052272719841058100111", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" ], "node_aux": { "key": "3", "value": "8" }}`; + const p = Proof.fromJSON(JSON.parse(given)); + + expect(proof.allSiblings()).to.deep.equal(p.allSiblings()); + expect(proof.nodeAux).to.deep.equal(p.nodeAux); + expect(proof.existence).to.equal(p.existence); + + let isValid = await verifyProof(await mt.root(), proof, BigInt('11'), BigInt('0')); + expect(isValid).to.be.true; + isValid = await verifyProof(await mt.root(), p, BigInt('11'), BigInt('0')); + expect(isValid).to.be.true; + }); }); } From 6b62f646aa9e0e46fa8321c90e3cdc8ad73f5ab6 Mon Sep 17 00:00:00 2001 From: vmidyllic <74898029+vmidyllic@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:40:27 +0300 Subject: [PATCH 2/6] node aux backward compatibility fix --- src/lib/merkletree/proof.ts | 13 +++++++++---- tests/full.test.ts | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/lib/merkletree/proof.ts b/src/lib/merkletree/proof.ts index 8c88b01..e88e1b3 100644 --- a/src/lib/merkletree/proof.ts +++ b/src/lib/merkletree/proof.ts @@ -10,7 +10,11 @@ import { Bytes } from '../../types'; export interface ProofJSON { existence: boolean; siblings: string[]; - node_aux: NodeAuxJSON | undefined; + node_aux: NodeAuxJSON | undefined; // this is a right representation of auxiliary node field according to the specification, nodeAux will be deprecated. + /** + * @deprecated old version is deprecated, do not use it. + */ + nodeAux: NodeAuxJSON | undefined; // old version of representation of auxiliary node. } export interface NodeAuxJSON { @@ -95,10 +99,11 @@ export class Proof { public static fromJSON(obj: ProofJSON): Proof { let nodeAux: NodeAux | undefined = undefined; - if (obj.node_aux) { + let nodeAuxJson: NodeAuxJSON | undefined = obj.node_aux ?? obj.nodeAux ?? undefined; // we keep backward compatibility and support both representations + if (nodeAuxJson) { nodeAux = { - key: Hash.fromString(obj.node_aux.key), - value: Hash.fromString(obj.node_aux.value) + key: Hash.fromString(nodeAuxJson.key), + value: Hash.fromString(nodeAuxJson.value) }; } const existence = obj.existence ?? false; diff --git a/tests/full.test.ts b/tests/full.test.ts index 5af9188..c4bcbbc 100644 --- a/tests/full.test.ts +++ b/tests/full.test.ts @@ -4,7 +4,13 @@ import { NodeLeaf, NodeMiddle } from '../src/lib/node/node'; import { InMemoryDB, LocalStorageDB, IndexedDBStorage } from '../src/lib/db'; import { bigIntToUINT8Array, bytes2Hex, bytesEqual, str2Bytes } from '../src/lib/utils'; import { Hash, ZERO_HASH } from '../src/lib/hash/hash'; -import { Merkletree, Proof, siblignsFroomProof, verifyProof } from '../src/lib/merkletree'; +import { + Merkletree, + Proof, + ProofJSON, + siblignsFroomProof, + verifyProof +} from '../src/lib/merkletree'; import { ErrEntryIndexAlreadyExists, ErrKeyNotFound, ErrReachedMaxLevel } from '../src/lib/errors'; import { expect } from 'chai'; @@ -1097,7 +1103,31 @@ for (let index = 0; index < storages.length; index++) { await tree.walk(await tree.root(), (node: Node) => f(node)); }); - it('proof stringify', async () => { + it('proof stringify (old format for node aux)', async () => { + const tree = new Merkletree(new InMemoryDB(str2Bytes('')), true, 40); + + for (let i = 0; i < 5; i++) { + await tree.add(BigInt(i), BigInt(i)); + } + + const { proof, value } = await tree.generateProof(BigInt(9)); + + const proofModel = JSON.stringify(proof); + const p = JSON.parse(proofModel) as ProofJSON; + + p.nodeAux = p.node_aux; + p.node_aux = undefined; + + const proofFromJSON = Proof.fromJSON(JSON.parse(proofModel)); + + expect(JSON.stringify(proof.allSiblings())).to.equal( + JSON.stringify(proofFromJSON.allSiblings()) + ); + expect(proof.existence).to.eq(proofFromJSON.existence); + expect(proof.existence).to.eq(false); + expect(JSON.stringify(proof.nodeAux)).to.eq(JSON.stringify(proofFromJSON.nodeAux)); + }); + it('proof stringify (new format for node aux)', async () => { const tree = new Merkletree(new InMemoryDB(str2Bytes('')), true, 40); for (let i = 0; i < 5; i++) { From f62bbd0244dcc24211756e13ab61b0d482832589 Mon Sep 17 00:00:00 2001 From: vmidyllic <74898029+vmidyllic@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:43:18 +0300 Subject: [PATCH 3/6] fix --- src/lib/merkletree/proof.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/merkletree/proof.ts b/src/lib/merkletree/proof.ts index e88e1b3..6e65027 100644 --- a/src/lib/merkletree/proof.ts +++ b/src/lib/merkletree/proof.ts @@ -99,7 +99,7 @@ export class Proof { public static fromJSON(obj: ProofJSON): Proof { let nodeAux: NodeAux | undefined = undefined; - let nodeAuxJson: NodeAuxJSON | undefined = obj.node_aux ?? obj.nodeAux ?? undefined; // we keep backward compatibility and support both representations + const nodeAuxJson: NodeAuxJSON | undefined = obj.node_aux ?? obj.nodeAux ?? undefined; // we keep backward compatibility and support both representations if (nodeAuxJson) { nodeAux = { key: Hash.fromString(nodeAuxJson.key), From 74f7cd9f5032a44639ef6e90ec264a78e8a9e3f7 Mon Sep 17 00:00:00 2001 From: vmidyllic <74898029+vmidyllic@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:44:13 +0300 Subject: [PATCH 4/6] 1.3.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4bb383d..dc62329 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@iden3/js-merkletree", - "version": "1.2.0", + "version": "1.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@iden3/js-merkletree", - "version": "1.2.0", + "version": "1.3.0", "license": "AGPL-3.0", "devDependencies": { "@iden3/eslint-config": "https://github.com/iden3/eslint-config", diff --git a/package.json b/package.json index 5bc7aef..4da6f27 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@iden3/js-merkletree", - "version": "1.2.0", + "version": "1.3.0", "description": "javascript sparse merkle tree library", "types": "dist/types/index.d.ts", "main": "dist/node/cjs/index.js", From e7e466861d04b365c0aeabec82f63d89a16a62aa Mon Sep 17 00:00:00 2001 From: vmidyllic <74898029+vmidyllic@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:45:07 +0300 Subject: [PATCH 5/6] fix --- src/lib/merkletree/proof.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/merkletree/proof.ts b/src/lib/merkletree/proof.ts index 6e65027..23c8f1d 100644 --- a/src/lib/merkletree/proof.ts +++ b/src/lib/merkletree/proof.ts @@ -99,7 +99,7 @@ export class Proof { public static fromJSON(obj: ProofJSON): Proof { let nodeAux: NodeAux | undefined = undefined; - const nodeAuxJson: NodeAuxJSON | undefined = obj.node_aux ?? obj.nodeAux ?? undefined; // we keep backward compatibility and support both representations + const nodeAuxJson: NodeAuxJSON | undefined = obj.node_aux ?? obj.nodeAux; // we keep backward compatibility and support both representations if (nodeAuxJson) { nodeAux = { key: Hash.fromString(nodeAuxJson.key), From d1305efc297f3fc9aa9180b28ac25d42e0967f64 Mon Sep 17 00:00:00 2001 From: vmidyllic <74898029+vmidyllic@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:48:55 +0300 Subject: [PATCH 6/6] add test with old format --- tests/full.test.ts | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/full.test.ts b/tests/full.test.ts index c4bcbbc..6e73885 100644 --- a/tests/full.test.ts +++ b/tests/full.test.ts @@ -1213,7 +1213,7 @@ for (let index = 0; index < storages.length; index++) { expect(cvp.value.string()).to.be.equal('22'); expect(cvp.fnc).to.be.equal(0); }); - it('calcualte depth for mtp', async () => { + it('calculate depth for mtp', async () => { const storage = getTreeStorage('calculatedepth'); const mt = new Merkletree(storage, true, 40); @@ -1231,6 +1231,29 @@ for (let index = 0; index < storages.length; index++) { expect(proof.nodeAux).to.deep.equal(p.nodeAux); expect(proof.existence).to.equal(p.existence); + let isValid = await verifyProof(await mt.root(), proof, BigInt('11'), BigInt('0')); + expect(isValid).to.be.true; + isValid = await verifyProof(await mt.root(), p, BigInt('11'), BigInt('0')); + expect(isValid).to.be.true; + }); + it('calculate depth for mtp (old format)', async () => { + const storage = getTreeStorage('calculatedepth'); + const mt = new Merkletree(storage, true, 40); + + await mt.add(BigInt('1'), BigInt('2')); + await mt.add(BigInt('3'), BigInt('8')); + await mt.add(BigInt('7'), BigInt('8')); + await mt.add(BigInt('9'), BigInt('8')); + + const { proof }: { proof: Proof } = await mt.generateProof(BigInt('11'), await mt.root()); + + const given = `{ "existence": false, "siblings": [ "0", "12166698708103333637493481507263348370172773813051235807348785759284762677336", "7750564177398573185975752951631372712868228752107043582052272719841058100111", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" ], "nodeAux": { "key": "3", "value": "8" }}`; + const p = Proof.fromJSON(JSON.parse(given)); + + expect(proof.allSiblings()).to.deep.equal(p.allSiblings()); + expect(proof.nodeAux).to.deep.equal(p.nodeAux); + expect(proof.existence).to.equal(p.existence); + let isValid = await verifyProof(await mt.root(), proof, BigInt('11'), BigInt('0')); expect(isValid).to.be.true; isValid = await verifyProof(await mt.root(), p, BigInt('11'), BigInt('0'));