Skip to content

Commit

Permalink
Merge pull request #46 from iden3/fix/calculate-mtp-proof-depth
Browse files Browse the repository at this point in the history
calc depth in right way; sync json tags with golang implementation
  • Loading branch information
vmidyllic authored Aug 27, 2024
2 parents 9ffaf74 + d1305ef commit dc3a462
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 11 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
18 changes: 12 additions & 6 deletions src/lib/merkletree/proof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import { Bytes } from '../../types';
export interface ProofJSON {
existence: boolean;
siblings: string[];
nodeAux: 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 {
Expand All @@ -28,7 +32,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);
Expand Down Expand Up @@ -66,7 +70,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()
Expand All @@ -87,17 +91,19 @@ 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 };
}

public static fromJSON(obj: ProofJSON): Proof {
let nodeAux: NodeAux | undefined = undefined;
if (obj.nodeAux) {
const nodeAuxJson: NodeAuxJSON | undefined = obj.node_aux ?? obj.nodeAux; // we keep backward compatibility and support both representations
if (nodeAuxJson) {
nodeAux = {
key: Hash.fromString(obj.nodeAux.key),
value: Hash.fromString(obj.nodeAux.value)
key: Hash.fromString(nodeAuxJson.key),
value: Hash.fromString(nodeAuxJson.value)
};
}
const existence = obj.existence ?? false;
Expand Down
80 changes: 78 additions & 2 deletions tests/full.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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++) {
Expand Down Expand Up @@ -1183,6 +1213,52 @@ for (let index = 0; index < storages.length; index++) {
expect(cvp.value.string()).to.be.equal('22');
expect(cvp.fnc).to.be.equal(0);
});
it('calculate 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;
});
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'));
expect(isValid).to.be.true;
});
});
}

Expand Down

0 comments on commit dc3a462

Please sign in to comment.