Skip to content

Commit dc3a462

Browse files
authored
Merge pull request #46 from iden3/fix/calculate-mtp-proof-depth
calc depth in right way; sync json tags with golang implementation
2 parents 9ffaf74 + d1305ef commit dc3a462

File tree

4 files changed

+93
-11
lines changed

4 files changed

+93
-11
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@iden3/js-merkletree",
3-
"version": "1.2.0",
3+
"version": "1.3.0",
44
"description": "javascript sparse merkle tree library",
55
"types": "dist/types/index.d.ts",
66
"main": "dist/node/cjs/index.js",

src/lib/merkletree/proof.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import { Bytes } from '../../types';
1010
export interface ProofJSON {
1111
existence: boolean;
1212
siblings: string[];
13-
nodeAux: NodeAuxJSON | undefined;
13+
node_aux: NodeAuxJSON | undefined; // this is a right representation of auxiliary node field according to the specification, nodeAux will be deprecated.
14+
/**
15+
* @deprecated old version is deprecated, do not use it.
16+
*/
17+
nodeAux: NodeAuxJSON | undefined; // old version of representation of auxiliary node.
1418
}
1519

1620
export interface NodeAuxJSON {
@@ -28,7 +32,7 @@ export class Proof {
2832

2933
constructor(obj?: { siblings: Siblings; nodeAux: NodeAux | undefined; existence: boolean }) {
3034
this.existence = obj?.existence ?? false;
31-
this.depth = obj?.siblings.length ?? 0;
35+
this.depth = 0;
3236
this.nodeAux = obj?.nodeAux;
3337

3438
const { siblings, notEmpties } = this.reduceSiblings(obj?.siblings);
@@ -66,7 +70,7 @@ export class Proof {
6670
return {
6771
existence: this.existence,
6872
siblings: this.allSiblings().map((s) => s.toJSON()),
69-
nodeAux: this.nodeAux
73+
node_aux: this.nodeAux
7074
? {
7175
key: this.nodeAux.key.toJSON(),
7276
value: this.nodeAux.value.toJSON()
@@ -87,17 +91,19 @@ export class Proof {
8791
if (JSON.stringify(siblings[i]) !== JSON.stringify(ZERO_HASH)) {
8892
setBitBigEndian(notEmpties, i);
8993
reducedSiblings.push(sibling);
94+
this.depth = i + 1;
9095
}
9196
}
9297
return { notEmpties, siblings: reducedSiblings };
9398
}
9499

95100
public static fromJSON(obj: ProofJSON): Proof {
96101
let nodeAux: NodeAux | undefined = undefined;
97-
if (obj.nodeAux) {
102+
const nodeAuxJson: NodeAuxJSON | undefined = obj.node_aux ?? obj.nodeAux; // we keep backward compatibility and support both representations
103+
if (nodeAuxJson) {
98104
nodeAux = {
99-
key: Hash.fromString(obj.nodeAux.key),
100-
value: Hash.fromString(obj.nodeAux.value)
105+
key: Hash.fromString(nodeAuxJson.key),
106+
value: Hash.fromString(nodeAuxJson.value)
101107
};
102108
}
103109
const existence = obj.existence ?? false;

tests/full.test.ts

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ import { NodeLeaf, NodeMiddle } from '../src/lib/node/node';
44
import { InMemoryDB, LocalStorageDB, IndexedDBStorage } from '../src/lib/db';
55
import { bigIntToUINT8Array, bytes2Hex, bytesEqual, str2Bytes } from '../src/lib/utils';
66
import { Hash, ZERO_HASH } from '../src/lib/hash/hash';
7-
import { Merkletree, Proof, siblignsFroomProof, verifyProof } from '../src/lib/merkletree';
7+
import {
8+
Merkletree,
9+
Proof,
10+
ProofJSON,
11+
siblignsFroomProof,
12+
verifyProof
13+
} from '../src/lib/merkletree';
814
import { ErrEntryIndexAlreadyExists, ErrKeyNotFound, ErrReachedMaxLevel } from '../src/lib/errors';
915

1016
import { expect } from 'chai';
@@ -1097,7 +1103,31 @@ for (let index = 0; index < storages.length; index++) {
10971103
await tree.walk(await tree.root(), (node: Node) => f(node));
10981104
});
10991105

1100-
it('proof stringify', async () => {
1106+
it('proof stringify (old format for node aux)', async () => {
1107+
const tree = new Merkletree(new InMemoryDB(str2Bytes('')), true, 40);
1108+
1109+
for (let i = 0; i < 5; i++) {
1110+
await tree.add(BigInt(i), BigInt(i));
1111+
}
1112+
1113+
const { proof, value } = await tree.generateProof(BigInt(9));
1114+
1115+
const proofModel = JSON.stringify(proof);
1116+
const p = JSON.parse(proofModel) as ProofJSON;
1117+
1118+
p.nodeAux = p.node_aux;
1119+
p.node_aux = undefined;
1120+
1121+
const proofFromJSON = Proof.fromJSON(JSON.parse(proofModel));
1122+
1123+
expect(JSON.stringify(proof.allSiblings())).to.equal(
1124+
JSON.stringify(proofFromJSON.allSiblings())
1125+
);
1126+
expect(proof.existence).to.eq(proofFromJSON.existence);
1127+
expect(proof.existence).to.eq(false);
1128+
expect(JSON.stringify(proof.nodeAux)).to.eq(JSON.stringify(proofFromJSON.nodeAux));
1129+
});
1130+
it('proof stringify (new format for node aux)', async () => {
11011131
const tree = new Merkletree(new InMemoryDB(str2Bytes('')), true, 40);
11021132

11031133
for (let i = 0; i < 5; i++) {
@@ -1183,6 +1213,52 @@ for (let index = 0; index < storages.length; index++) {
11831213
expect(cvp.value.string()).to.be.equal('22');
11841214
expect(cvp.fnc).to.be.equal(0);
11851215
});
1216+
it('calculate depth for mtp', async () => {
1217+
const storage = getTreeStorage('calculatedepth');
1218+
const mt = new Merkletree(storage, true, 40);
1219+
1220+
await mt.add(BigInt('1'), BigInt('2'));
1221+
await mt.add(BigInt('3'), BigInt('8'));
1222+
await mt.add(BigInt('7'), BigInt('8'));
1223+
await mt.add(BigInt('9'), BigInt('8'));
1224+
1225+
const { proof }: { proof: Proof } = await mt.generateProof(BigInt('11'), await mt.root());
1226+
1227+
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" }}`;
1228+
const p = Proof.fromJSON(JSON.parse(given));
1229+
1230+
expect(proof.allSiblings()).to.deep.equal(p.allSiblings());
1231+
expect(proof.nodeAux).to.deep.equal(p.nodeAux);
1232+
expect(proof.existence).to.equal(p.existence);
1233+
1234+
let isValid = await verifyProof(await mt.root(), proof, BigInt('11'), BigInt('0'));
1235+
expect(isValid).to.be.true;
1236+
isValid = await verifyProof(await mt.root(), p, BigInt('11'), BigInt('0'));
1237+
expect(isValid).to.be.true;
1238+
});
1239+
it('calculate depth for mtp (old format)', async () => {
1240+
const storage = getTreeStorage('calculatedepth');
1241+
const mt = new Merkletree(storage, true, 40);
1242+
1243+
await mt.add(BigInt('1'), BigInt('2'));
1244+
await mt.add(BigInt('3'), BigInt('8'));
1245+
await mt.add(BigInt('7'), BigInt('8'));
1246+
await mt.add(BigInt('9'), BigInt('8'));
1247+
1248+
const { proof }: { proof: Proof } = await mt.generateProof(BigInt('11'), await mt.root());
1249+
1250+
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" }}`;
1251+
const p = Proof.fromJSON(JSON.parse(given));
1252+
1253+
expect(proof.allSiblings()).to.deep.equal(p.allSiblings());
1254+
expect(proof.nodeAux).to.deep.equal(p.nodeAux);
1255+
expect(proof.existence).to.equal(p.existence);
1256+
1257+
let isValid = await verifyProof(await mt.root(), proof, BigInt('11'), BigInt('0'));
1258+
expect(isValid).to.be.true;
1259+
isValid = await verifyProof(await mt.root(), p, BigInt('11'), BigInt('0'));
1260+
expect(isValid).to.be.true;
1261+
});
11861262
});
11871263
}
11881264

0 commit comments

Comments
 (0)