UNPKG

2.59 kBJavaScriptView Raw
1/**
2 * Merkle
3 * ======
4 *
5 * A node in a Merkle tree (possibly the root node, in which case it is the
6 * Merkle root). A node either contains a buffer or links to two other nodes.
7 */
8'use strict'
9
10import { Hash } from './hash'
11import { Struct } from './struct'
12
13class Merkle extends Struct {
14 constructor (hashBuf, buf, merkle1, merkle2) {
15 super({ hashBuf, buf, merkle1, merkle2 })
16 }
17
18 hash () {
19 if (this.hashBuf) {
20 return this.hashBuf
21 }
22 if (this.buf) {
23 return Hash.sha256Sha256(this.buf)
24 }
25 const hashBuf1 = this.merkle1.hash()
26 const hashBuf2 = this.merkle2.hash()
27 this.buf = Buffer.concat([hashBuf1, hashBuf2])
28 return Hash.sha256Sha256(this.buf)
29 }
30
31 fromBuffers (bufs) {
32 if (bufs.length < 1) {
33 throw new Error('buffers must have a length')
34 }
35 bufs = bufs.slice()
36 const log = Math.log2(bufs.length)
37 if (!Number.isInteger(log)) {
38 // If a merkle tree does not have a number of ends that is a power of 2,
39 // then we have to copy the last value until it is a power of 2. Note
40 // that we copy *the actual object* over and over again, which ensures
41 // that when we finds its hash, the hash is cached.
42 const lastval = bufs[bufs.length - 1]
43 var len = Math.pow(2, Math.ceil(log))
44 for (let i = bufs.length; i < len; i++) {
45 bufs.push(lastval)
46 }
47 }
48 const bufs1 = bufs.slice(0, bufs.length / 2)
49 const bufs2 = bufs.slice(bufs.length / 2)
50 this.fromBufferArrays(bufs1, bufs2)
51 return this
52 }
53
54 static fromBuffers (bufs) {
55 return new this().fromBuffers(bufs)
56 }
57
58 /**
59 * Takes two arrays, both of which *must* be of a length that is a power of
60 * two.
61 */
62 fromBufferArrays (bufs1, bufs2) {
63 if (bufs1.length === 1) {
64 this.merkle1 = new Merkle(undefined, bufs1[0])
65 this.merkle2 = new Merkle(undefined, bufs2[0])
66 return this
67 }
68 const bufs11 = bufs1.slice(0, bufs1.length / 2)
69 const bufs12 = bufs1.slice(bufs1.length / 2)
70 this.merkle1 = new Merkle().fromBufferArrays(bufs11, bufs12)
71 const bufs21 = bufs2.slice(0, bufs2.length / 2)
72 const bufs22 = bufs2.slice(bufs2.length / 2)
73 this.merkle2 = new Merkle().fromBufferArrays(bufs21, bufs22)
74 return this
75 }
76
77 static fromBufferArrays (bufs1, bufs2) {
78 return new this().fromBufferArrays(bufs1, bufs2)
79 }
80
81 leavesNum () {
82 if (this.merkle1) {
83 return this.merkle1.leavesNum() + this.merkle2.leavesNum()
84 }
85 if (this.buf) {
86 return 1
87 }
88 throw new Error('invalid number of leaves')
89 }
90}
91
92export { Merkle }