Skip to content

Commit

Permalink
#133 CID rank merkle proofs. Merkle tree proofs fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
arturalbov authored and hleb-albau committed Dec 28, 2018
1 parent 8cf6666 commit 04e54a1
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 58 deletions.
23 changes: 23 additions & 0 deletions merkle/proof.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package merkle

import "crypto/sha256"

type Proof struct {
left bool // where proof should be placed for concat with hash (left or right)
hash []byte
}

// calculate sum hash
func (p *Proof) ConcatWith(hash []byte) []byte {
h := sha256.New()

if p.left {
h.Write(p.hash)
h.Write(hash)
} else {
h.Write(hash)
h.Write(p.hash)
}

return h.Sum(nil)
}
49 changes: 33 additions & 16 deletions merkle/tree.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package merkle

import (
"bytes"
"crypto/sha256"
"math"
)
Expand All @@ -14,30 +15,30 @@ type Subtree struct {
height int
}

func (t *Subtree) GetTreeProofs() [][]byte {
proofs := make([][]byte, 0)
func (t *Subtree) GetRootProofs() []Proof {
proofs := make([]Proof, 0)

proofs = append(proofs, t.getRightProofs()...)
proofs = append(proofs, t.getLeftProofs()...)

return proofs
}

func (t *Subtree) getLeftProofs() [][]byte {
proofs := make([][]byte, 0, 1)
func (t *Subtree) getLeftProofs() []Proof {
proofs := make([]Proof, 0, 1)
current := t.left
for current != nil {
proofs = append(proofs, current.root.hash)
proofs = append(proofs, Proof{hash: current.root.hash, left: false})
current = current.left
}
return proofs
}

// right proof is only one cause we have to merge all right trees
func (t *Subtree) getRightProofs() [][]byte {
func (t *Subtree) getRightProofs() []Proof {

if t.right == nil {
return make([][]byte, 0)
return make([]Proof, 0)
}

hashesToSum := make([][]byte, 0)
Expand All @@ -57,7 +58,7 @@ func (t *Subtree) getRightProofs() [][]byte {
proofHash = h.Sum(nil)
}

return [][]byte{proofHash}
return []Proof{{hash: proofHash, left: true}}
}

type Node struct {
Expand All @@ -73,17 +74,17 @@ type Node struct {
lastIndex int
}

func (n *Node) GetIndexProofs(i int) [][]byte {
proofs := make([][]byte, 0)
func (n *Node) GetIndexProofs(i int) []Proof {
proofs := make([]Proof, 0)

if n.left != nil && i >= n.left.firstIndex && i <= n.left.lastIndex {
proofs = n.left.GetIndexProofs(i)
proofs = append(proofs, n.right.hash)
proofs = append(proofs, Proof{hash: n.right.hash, left: false})
}

if n.right != nil && i >= n.right.firstIndex && i <= n.right.lastIndex {
proofs = n.right.GetIndexProofs(i)
proofs = append(proofs, n.left.hash)
proofs = append(proofs, Proof{hash: n.left.hash, left: true})
}

return proofs
Expand All @@ -106,7 +107,6 @@ func NewTree() Tree {
return Tree{}
}

// only for root tree
func (t *Tree) joinAllSubtrees() {

for t.subTree.left != nil && t.subTree.height == t.subTree.left.height {
Expand Down Expand Up @@ -175,15 +175,15 @@ func (t *Tree) Push(data []byte) {
}

// going from right trees to left
func (t *Tree) GetIndexProofs(i int) [][]byte {
func (t *Tree) GetIndexProofs(i int) []Proof {

proofs := make([][]byte, 0, int64(math.Log2(float64(t.lastIndex))))
proofs := make([]Proof, 0, int64(math.Log2(float64(t.lastIndex))))

for current := t.subTree; current != nil; {

if i >= current.root.firstIndex && i <= current.root.lastIndex {
proofs = append(proofs, current.root.GetIndexProofs(i)...)
proofs = append(proofs, current.GetTreeProofs()...)
proofs = append(proofs, current.GetRootProofs()...)
return proofs
}

Expand All @@ -193,6 +193,23 @@ func (t *Tree) GetIndexProofs(i int) [][]byte {
return proofs
}

func (t *Tree) ValidateIndex(i int, data []byte) bool {
return t.ValidateIndexByProofs(i, data, t.GetIndexProofs(i))
}

func (t *Tree) ValidateIndexByProofs(i int, data []byte, proofs []Proof) bool {

h := sha256.New()
h.Write(data)

rootHash := h.Sum(nil)
for _, proof := range proofs {
rootHash = proof.ConcatWith(rootHash)
}

return bytes.Equal(rootHash, t.GetRootHash())
}

func (t *Tree) GetRootHash() []byte {

if t.subTree == nil {
Expand Down
48 changes: 6 additions & 42 deletions merkle/tree_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package merkle

import (
"crypto/sha256"
"encoding/binary"
"github.com/stretchr/testify/require"
"testing"
Expand All @@ -18,46 +17,11 @@ func TestProofs(t *testing.T) {
tree.Push(data)
}

indexToProof := 25
proofs := tree.GetIndexProofs(indexToProof)

require.Equal(t, 5, len(proofs))

binary.LittleEndian.PutUint64(data, uint64(indexToProof))
h := sha256.New()
h.Write(data)

rootHash := h.Sum(nil)

h.Reset()
h.Write(proofs[0])
h.Write(rootHash)

rootHash = h.Sum(nil)

h.Reset()
h.Write(rootHash)
h.Write(proofs[1])

rootHash = h.Sum(nil)

h.Reset()
h.Write(proofs[2])
h.Write(rootHash)

rootHash = h.Sum(nil)

h.Reset()
h.Write(rootHash)
h.Write(proofs[3])

rootHash = h.Sum(nil)

h.Reset()
h.Write(rootHash)
h.Write(proofs[4])

rootHash = h.Sum(nil)
// Check all proofs
for i := 0; i < 31; i++ {
proofs := tree.GetIndexProofs(i)
binary.LittleEndian.PutUint64(data, uint64(i))
require.Equal(t, true, tree.ValidateIndexByProofs(i, data, proofs))
}

require.Equal(t, rootHash, tree.hash)
}

0 comments on commit 04e54a1

Please sign in to comment.