forked from google/certificate-transparency
-
Notifications
You must be signed in to change notification settings - Fork 0
/
merkle_tree.go
131 lines (114 loc) · 3.94 KB
/
merkle_tree.go
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package merkletree
/*
#cgo LDFLAGS: -lcrypto
#cgo CPPFLAGS: -I../../cpp
#cgo CXXFLAGS: -std=c++11
#include "merkle_tree_go.h"
*/
import "C"
import (
"errors"
"fmt"
)
// CPPMerkleTree provides an interface to the C++ CT MerkleTree library.
// See the go/README file for details on how to build this.
type CPPMerkleTree struct {
FullMerkleTreeInterface
// The C++ MerkleTree handle
peer C.TREE
// nodeSize contains the size in bytes of the nodes in the MerkleTree
// referenced by |peer|.
nodeSize C.size_t
}
func (m *CPPMerkleTree) LeafCount() uint64 {
return uint64(C.LeafCount(m.peer))
}
func (m *CPPMerkleTree) LevelCount() uint64 {
return uint64(C.LevelCount(m.peer))
}
func (m *CPPMerkleTree) AddLeaf(leaf []byte) uint64 {
return uint64(C.AddLeaf(m.peer, C.BYTE_SLICE(&leaf)))
}
func (m *CPPMerkleTree) AddLeafHash(hash []byte) uint64 {
return uint64(C.AddLeafHash(m.peer, C.BYTE_SLICE(&hash)))
}
func (m *CPPMerkleTree) LeafHash(leaf uint64) ([]byte, error) {
hash := make([]byte, m.nodeSize)
success := C.LeafHash(m.peer, C.BYTE_SLICE(&hash), C.size_t(leaf))
if !success {
return nil, fmt.Errorf("failed to get leafhash of leaf %d", leaf)
}
return hash, nil
}
func (m *CPPMerkleTree) CurrentRoot() ([]byte, error) {
hash := make([]byte, m.nodeSize)
success := C.CurrentRoot(m.peer, C.BYTE_SLICE(&hash))
if !success {
return nil, errors.New("failed to get current root")
}
return hash, nil
}
func (m *CPPMerkleTree) RootAtSnapshot(snapshot uint64) ([]byte, error) {
hash := make([]byte, m.nodeSize)
success := C.RootAtSnapshot(m.peer, C.BYTE_SLICE(&hash), C.size_t(snapshot))
if !success {
return nil, fmt.Errorf("failed to get root at snapshot %d", snapshot)
}
return hash, nil
}
func splitSlice(slice []byte, chunkSize int) ([][]byte, error) {
if len(slice)%chunkSize != 0 {
return nil, fmt.Errorf("slice len %d is not a multiple of chunkSize %d", len(slice), chunkSize)
}
numEntries := len(slice) / chunkSize
ret := make([][]byte, numEntries)
for i := 0; i < numEntries; i++ {
start := i * chunkSize
end := start + chunkSize
ret[i] = slice[start:end]
}
return ret, nil
}
func (m *CPPMerkleTree) PathToCurrentRoot(leaf uint64) ([][]byte, error) {
var numEntries C.size_t
entryBuffer := make([]byte, C.size_t(m.LevelCount())*m.nodeSize)
success := C.PathToCurrentRoot(m.peer, C.BYTE_SLICE(&entryBuffer), &numEntries, C.size_t(leaf))
if !success {
return nil, fmt.Errorf("failed to get path to current root from leaf %d", leaf)
}
return splitSlice(entryBuffer, int(m.nodeSize))
}
func (m *CPPMerkleTree) PathToRootAtSnapshot(leaf, snapshot uint64) ([][]byte, error) {
var num_entries C.size_t
entryBuffer := make([]byte, C.size_t(m.LevelCount())*m.nodeSize)
success := C.PathToRootAtSnapshot(m.peer, C.BYTE_SLICE(&entryBuffer), &num_entries, C.size_t(leaf), C.size_t(snapshot))
if !success {
return nil, fmt.Errorf("failed to get path to root at snapshot %d from leaf %d", snapshot, leaf)
}
return splitSlice(entryBuffer, int(m.nodeSize))
}
func (m *CPPMerkleTree) SnapshotConsistency(snapshot1, snapshot2 uint64) ([][]byte, error) {
var num_entries C.size_t
entryBuffer := make([]byte, C.size_t(m.LevelCount())*m.nodeSize)
success := C.SnapshotConsistency(m.peer, C.BYTE_SLICE(&entryBuffer), &num_entries, C.size_t(snapshot1), C.size_t(snapshot2))
if !success {
return nil, fmt.Errorf("failed to get path to snapshot consistency from %d to %d", snapshot1, snapshot2)
}
return splitSlice(entryBuffer, int(m.nodeSize))
}
// NewCPPMerkleTree returns a new wrapped C++ MerkleTree, using the
// Sha256Hasher.
// It is the caller's responsibility to call DeletePeer() when finished with
// the tree to deallocate its resources.
func NewCPPMerkleTree() *CPPMerkleTree {
m := &CPPMerkleTree{
peer: C.NewMerkleTree(C.NewSha256Hasher()),
}
m.nodeSize = C.size_t(C.NodeSize(m.peer))
return m
}
// DeletePeer deallocates the memory used by the C++ MerkleTree peer.
func (m *CPPMerkleTree) DeletePeer() {
C.DeleteMerkleTree(m.peer)
m.peer = nil
}