All files / src/util merkleTree.js

100% Statements 53/53
100% Branches 22/22
100% Functions 6/6
100% Lines 49/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74    8x 43x   42x 42x 15x     42x 42x 42x     8x 8x 1x     7x 7x 7x 7x 7x 42x 42x 42x 42x   19x 3x 3x     19x 19x     7x     8x 6x 6x   5x 5x 5x 5x 15x 15x 15x 15x 15x 15x 15x   5x     8x 1x 1x     8x 6x 6x 6x     24x  
import sha256 from './sha256';
 
const fromTwoBuffers = data => {
  if (data.length !== 2) throw new TypeError('Wrong data size.');
 
  const compared = Buffer.compare(data[0], data[1]);
  if (compared > 0) {
    data.reverse();
  }
 
  let buffer = Buffer.concat(data);
  buffer = Buffer.from(sha256(buffer), 'hex');
  return buffer;
};
 
const generateMerkleTree = data => {
  if (data.length === 0) {
    return null;
  }
 
  if (data.length % 2 === 1) { data.push(data[data.length - 1]); }
  let nodeToAdd = data.length / 2;
  let newAdded = 0;
  let i = 0;
  while (i < data.length - 1) {
    const left = data[i++];
    const right = data[i++];
    data.push(fromTwoBuffers([left, right]));
    if (++newAdded === nodeToAdd) {
      // complete this row
      if (nodeToAdd % 2 === 1 && nodeToAdd !== 1) {
        nodeToAdd++;
        data.push(data[data.length - 1]);
      }
      // start a new row
      nodeToAdd /= 2;
      newAdded = 0;
    }
  }
  return data;
};
 
const generateMerklePath = (indexArg, leafCount, tree) => {
  let index = indexArg;
  if (tree.length === 0 || index >= leafCount) return null;
 
  let firstInRow = 0;
  let rowcount = leafCount;
  const path = [];
  while (index < tree.length - 1) {
    const neighbor = index % 2 === 0 ? index + 1 : index - 1;
    path.push(tree[neighbor]);
    rowcount = rowcount % 2 === 0 ? rowcount : rowcount + 1;
    const shift = Math.floor((index - firstInRow) / 2);
    firstInRow += rowcount;
    index = firstInRow + shift;
    rowcount /= 2;
  }
  return path;
};
 
export const computeRoot = data => {
  const merkleTree = generateMerkleTree(data);
  return merkleTree[merkleTree.length - 1];
};
 
export const getMerklePath = (index, data) => {
  const leafCount = data.length;
  const merkleTree = generateMerkleTree(data);
  return generateMerklePath(index, leafCount, merkleTree);
};
 
export const node = buffer => Buffer.from(sha256(buffer), 'hex');