UNPKG

merkle-heap-snarkyjs

Version:

Implementation of a Merkle Heap for SnarkyJS, a framework to develop ZK-snarks on Mina Protocol.

299 lines (276 loc) 12.1 kB
import { isReady, shutdown, Poseidon, Field, MerkleTree, MerkleWitness, UInt64, UInt32, Int64 } from 'snarkyjs'; import { MerkleHeap } from '../src/MerkleHeap'; import { customAlphabet } from 'nanoid'; describe('Merkle Heap', () => { beforeAll(async () => { await isReady; }); beforeEach(async () => { await isReady; }); afterAll(async () => { setTimeout(shutdown, 300000); }); //Functions //Test for constructor function //If the heap was initialized succesfully so it is empty the root should correspont to the hash of the child nodes which are Field(0) and its hashes. //In the case of Heigh=3 the root must be equal to the H(h(Field(0),h(Field(0)))) it('Initializing an empty Merkle Heap', async () => { const merkleHeap = new MerkleHeap(2); let merkleRoot = merkleHeap.getRoot(); console.log(merkleRoot); let hashOfZeroes = Poseidon.hash([new Field(0), new Field(0)]); let hashOfHashOfZeroes = Poseidon.hash([hashOfZeroes, hashOfZeroes]); expect(hashOfHashOfZeroes).toEqual(merkleRoot); }); //Tests for insert functionß //We need to test that the Heap property is correct after n number of insertions //We use a function to fill the Merkle heap with random values and then test the Heap property describe('Insert function test', () => { it('Verifies Heap property after fill the tree for Height=3', async () => { // //For H=3 const nanoid = customAlphabet('1234567890', 4); const HEIGHT = 3; let nodes = 2 ** HEIGHT - 1; const merkleHeap = new MerkleHeap(HEIGHT); console.log('NODES=>', nodes); try { //F illing the entire Tree with Random values for (let index = 0; index < nodes; index++) { // console.log('Insertion Index =>',index); let valueInsterted =Field(nanoid()) merkleHeap.insert(valueInsterted); console.log('Value inserted =>',valueInsterted, 'in iteration number',index ) } // Verifying Heap property for a Min Heap // # of Nodes = (2^H)-1 //TODO:FIX console.log('HEIGHT=>', merkleHeap.height); // The father is the root node let currentFather = merkleHeap.getMerkleTreeLeaf(0n); console.log('current number', currentFather?.toBigInt()); for (let i = 0; i < nodes && currentFather !== null; i++) { console.log('ITERATION NUMBER', i); console.log('CHILDREN'); let children = merkleHeap.getChildIndexesOfFather(BigInt(i)); console.log(children); let childrenLeftValue = merkleHeap.getMerkleTreeLeaf(children.left); console.log('LEFT CHILD VALUE', childrenLeftValue); let childrenRightValue = merkleHeap.getMerkleTreeLeaf(children.right); console.log('RIGHT CHILD VALUE ', childrenRightValue); if (childrenLeftValue !== null) { expect(childrenLeftValue?.toBigInt()).toBeGreaterThanOrEqual( currentFather.toBigInt() ); } if (childrenRightValue !== null) { expect(childrenRightValue?.toBigInt()).toBeGreaterThanOrEqual( currentFather.toBigInt() ); } currentFather = merkleHeap.getMerkleTreeLeaf(BigInt(i + 1)); } } catch (error) { console.error(JSON.stringify(error, null, 2)); throw error; } }); }); //We need to test that after n number insertions we are deleting the min number. //Also we need to test that this nummber does not live in the Heap anymore. describe('Delete Min function test', () => { it('Verifies that the min number is being deleted', async () => { const merkleHeap = new MerkleHeap(2); const minValue1= Field(1); // console.log('Min Value1=>',minValue1.toConstant()) // console.log(minValue1.assertEquals(-1)) const minValue2= Field(480) const minValue3= Field(10289838) merkleHeap.insert(minValue1) merkleHeap.insert(minValue2) merkleHeap.insert(minValue3) const firstDeletion= merkleHeap.deleteMin() //For veryfing that the value is not anymore in the queue I use the inQueue function const isFirstDeletionInQueue=merkleHeap.inQueue(minValue1) expect(isFirstDeletionInQueue).toBe(false) console.log('Is first in queue?', isFirstDeletionInQueue) console.log('First Deletion',firstDeletion?.toBigInt()) expect(firstDeletion?.toBigInt()).toBe(minValue1?.toBigInt()) const secondDeletion= merkleHeap.deleteMin() const isSecondDeletionInQueue=merkleHeap.inQueue(minValue2) expect(isSecondDeletionInQueue).toBe(false) expect(secondDeletion?.toBigInt()).toBe(minValue2?.toBigInt()) console.log('Second Deletion',secondDeletion) const thirdDeletion= merkleHeap.deleteMin() const isThirdDeletionInQueue=merkleHeap.inQueue(minValue3) expect(isThirdDeletionInQueue).toBe(false) console.log('Third Deletion',thirdDeletion) expect(thirdDeletion?.toBigInt()).toBe(minValue3.toBigInt()) }); }); describe('Delete Element at index function test', () => { it('Should delete the element in a specific index', async () => { //In case of a Min Heap, the least value is the root or father //So after deleting the min Element, the father should change //And the value that was deleted should have been the father // let currentFather = merkleHeap.getMerkleTreeLeaf(0n); const HEIGHT = 2 const merkleHeap = new MerkleHeap(HEIGHT); // let firstNumberToDelete = // const firstValuetest= Int64.fromField(Field(1)); // const test1= Int64.fromField(Field(-44)); // const conditionTest=test1>firstValuetest // console.log('THIS IS A FREAKING TEST',conditionTest) // console.log('CONDITION',firstValue.assertEquals(-1)) // console.log('FIRST VALUE => ',Int64.fromField(firstValue)) const firstValue= Field(1); const secondValue= Field(480) // console.log('SECOND VALUE => ',secondValue.toBigInt()) const thirdValue= Field(10289838) merkleHeap.insert(firstValue) merkleHeap.insert(secondValue) merkleHeap.insert(thirdValue) //the heap structure should be 0n:Field(1),1n:Field(480) || 1n:Field(10289838) ,2n:Field(480) || 1n:Field(10289838) const firstDeletion= merkleHeap.deleteElementAtIndex(0n) console.log('first delation => ',firstDeletion) expect(firstDeletion?.toBigInt()).toBe(firstDeletion?.toBigInt()) //For veryfing that the value is not anymore in the queue I use the inQueue function const isFirstDeletionInQueue=merkleHeap.inQueue(firstValue) expect(isFirstDeletionInQueue).toBe(false) console.log('Is first in queue?', isFirstDeletionInQueue) // console.log('First Deletion',firstDeletion?.toBigInt()) const secondDeletion= merkleHeap.deleteElementAtIndex(0n) // console.log('2 delation => ',secondDeletion?.toBigInt()) const thirdDeletion= merkleHeap.deleteElementAtIndex(0n) console.log('THIRD DELETION', thirdDeletion?.toBigInt()) // console.log('3rd delation => ',thirdDeletion?.toBigInt()) const isSecondDeletionInQueue=merkleHeap.inQueue(secondValue) const isThirdDeletionInQueue=merkleHeap.inQueue(thirdValue) expect(isSecondDeletionInQueue).toBe(false) expect(secondDeletion?.toBigInt()).toBe(secondValue?.toBigInt()) expect(isThirdDeletionInQueue).toBe(false) expect(thirdDeletion?.toBigInt()).toBe(thirdValue.toBigInt()) // expect(firstElement).toBe(6) }); }); /** * This function tests that after multiple inserts, the function is verifying correctly if the value is part of the queue or not. */ describe('isInqueue function test', () => { it('Verifies that the numbers that are not in queue are not there and after multiple insertions these numbers are added to the queue', async () => { const merkleHeap = new MerkleHeap(2); const testValue1= Field(0); const testValue2= Field(-10); const testValue3= Field(40); const testValue4= Field(-0); // console.log('Min Value1=>',minValue1.toConstant()) // console.log(minValue1.assertEquals(-1)) const insertValue1= Field(92727282) const insertValue2= Field(-20) const insertValue3= Field('2018') //Insertions merkleHeap.insert(insertValue1) merkleHeap.insert(insertValue2) merkleHeap.insert(insertValue3) const test1=merkleHeap.inQueue(testValue1) expect(test1).toBe(false) const test2=merkleHeap.inQueue(testValue2) expect(test2).toBe(false) const test3=merkleHeap.inQueue(testValue3) expect(test3).toBe(false) const test4=merkleHeap.inQueue(testValue4) expect(test4).toBe(false) const insertTest1=merkleHeap.inQueue(insertValue1) expect(insertTest1).toBe(true) const insertTest2=merkleHeap.inQueue(insertValue2) expect(insertTest2).toBe(true) const insertTest3=merkleHeap.inQueue(insertValue3) expect(insertTest3).toBe(true) }); }); /** * This function tests that the min number in the queue is being found after multiple insertions and deletions */ describe('findMin function test', () => { it('Verifies that the findMin function works properly after multiple insertions and deletions, using the delete min function', async () => { //Init const merkleHeap = new MerkleHeap(3); //Values //TODO: Add support to negative values const minValue1= Field(-0); const minValue2= Field(0) const minValue3= Field(1) // const minValue4= Field(2) // //insertions merkleHeap.insert(minValue1) merkleHeap.insert(minValue2) merkleHeap.insert(minValue3) //TODO:ERROR HERE // merkleHeap.insert(minValue4) const firstTest=merkleHeap.findMin() expect(firstTest).toBe(minValue1) merkleHeap.deleteMin() const secondTest=merkleHeap.findMin() expect(secondTest).toBe(minValue2) merkleHeap.deleteMin() const thirdTest=merkleHeap.findMin() expect(thirdTest).toBe(minValue3) merkleHeap.deleteMin() //TODO:ERROR HERE // const fourthTest=merkleHeap.findMin() // expect(fourthTest).toBe(minValue4) // merkleHeap.deleteMin() // const finalTest=merkleHeap.findMin() // console.log('WHAT THE FUCK IS THIS?',finalTest) // // merkleHeap.deleteMin() }); }); /** * This function tests that the insertThenDeleteMin function does the following: * Inserts a value in the correct position and then extracts the root of the Tree */ describe('findMin function test', () => { it('Verifies that the findMin function works property after multiple insertions and deletions, using the delete min function', async () => { //Init const merkleHeap = new MerkleHeap(3); //Values //TODO: Add support to negative values const minValue1= Field(-0); const minValue2= Field(0) const minValue3= Field(1) // const minValue4= Field(2) // //insertions merkleHeap.insert(minValue1) merkleHeap.insert(minValue2) merkleHeap.insert(minValue3) //TODO:ERROR HERE // merkleHeap.insert(minValue4) const firstTest=merkleHeap.findMin() expect(firstTest).toBe(minValue1) merkleHeap.deleteMin() const secondTest=merkleHeap.findMin() expect(secondTest).toBe(minValue2) merkleHeap.deleteMin() const thirdTest=merkleHeap.findMin() expect(thirdTest).toBe(minValue3) merkleHeap.deleteMin() //TODO:ERROR HERE // const fourthTest=merkleHeap.findMin() // expect(fourthTest).toBe(minValue4) // merkleHeap.deleteMin() // const finalTest=merkleHeap.findMin() // console.log('WHAT THE FUCK IS THIS?',finalTest) // // merkleHeap.deleteMin() }); }); });