Skip to content

Commit bc8358c

Browse files
authored
Merge pull request google#1302 from AlCutter/go_c_merkle_tree
2 parents 8c298a6 + dab4dde commit bc8358c

File tree

4 files changed

+69
-79
lines changed

4 files changed

+69
-79
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,6 @@ script:
126126
- ${MAKE} -C python test
127127
- pushd ${GOPATH}
128128
- |
129-
GODEBUG=cgocheck=0 CGO_CPPFLAGS="-I${INSTALL_DIR}/include" CGO_LDFLAGS="-L${INSTALL_DIR}/lib" go test -v ./src/github.com/google/certificate-transparency/go/...
129+
CGO_CPPFLAGS="-I${INSTALL_DIR}/include" CGO_LDFLAGS="-L${INSTALL_DIR}/lib" go test -v ./src/github.com/google/certificate-transparency/go/...
130130
- popd
131131

go/merkletree/merkle_tree.go

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ package merkletree
88
*/
99
import "C"
1010
import (
11-
"errors"
1211
"fmt"
12+
"unsafe"
1313
)
1414

1515
// CPPMerkleTree provides an interface to the C++ CT MerkleTree library.
@@ -39,50 +39,56 @@ func (m *CPPMerkleTree) LevelCount() uint64 {
3939
// the tree structure, does not store the data itself.
4040
// Returns the position of the leaf in the tree.
4141
func (m *CPPMerkleTree) AddLeaf(leaf []byte) uint64 {
42-
return uint64(C.AddLeaf(m.peer, C.BYTE_SLICE(&leaf)))
42+
var leafPtr unsafe.Pointer
43+
// Don't flake out if we're passed an empty leaf slice.
44+
// We'll end up passing nullptr to the C++ code, but that's fine since we'll
45+
// also be passing a size of 0.
46+
if len(leaf) > 0 {
47+
leafPtr = unsafe.Pointer(&leaf[0])
48+
}
49+
return uint64(C.AddLeaf(m.peer, leafPtr, C.size_t(len(leaf))))
4350
}
4451

4552
// AddLeafHash adds a leaf hash directly to the tree. Returns the position of
4653
// the leaf in the tree.
4754
func (m *CPPMerkleTree) AddLeafHash(hash []byte) uint64 {
48-
return uint64(C.AddLeafHash(m.peer, C.BYTE_SLICE(&hash)))
55+
return uint64(C.AddLeafHash(m.peer, unsafe.Pointer(&hash[0]), C.size_t(len(hash))))
4956
}
5057

5158
// LeafHash returns the leaf hash for the leaf at the requested index.
5259
func (m *CPPMerkleTree) LeafHash(leaf uint64) ([]byte, error) {
5360
hash := make([]byte, m.nodeSize)
54-
success := C.LeafHash(m.peer, C.BYTE_SLICE(&hash), C.size_t(leaf))
55-
if !success {
56-
return nil, fmt.Errorf("failed to get leafhash of leaf %d", leaf)
61+
size := C.LeafHash(m.peer, C.size_t(leaf), unsafe.Pointer(&hash[0]), C.size_t(len(hash)))
62+
if got, want := size, m.nodeSize; got != want {
63+
return nil, fmt.Errorf("failed to get leafhash of leaf %d, got %d bytes expected %d", leaf, got, want)
5764
}
5865
return hash, nil
5966
}
6067

6168
// CurrentRoot returns the current root of the tree.
6269
func (m *CPPMerkleTree) CurrentRoot() ([]byte, error) {
6370
hash := make([]byte, m.nodeSize)
64-
success := C.CurrentRoot(m.peer, C.BYTE_SLICE(&hash))
65-
if !success {
66-
return nil, errors.New("failed to get current root")
71+
size := C.CurrentRoot(m.peer, unsafe.Pointer(&hash[0]), C.size_t(len(hash)))
72+
if got, want := size, m.nodeSize; got != want {
73+
return nil, fmt.Errorf("failed to get current root, got %d bytes, expected %d", got, want)
6774
}
6875
return hash, nil
6976
}
7077

7178
// RootAtSnapshot returns the root at a given index.
7279
func (m *CPPMerkleTree) RootAtSnapshot(snapshot uint64) ([]byte, error) {
7380
hash := make([]byte, m.nodeSize)
74-
success := C.RootAtSnapshot(m.peer, C.BYTE_SLICE(&hash), C.size_t(snapshot))
75-
if !success {
76-
return nil, fmt.Errorf("failed to get root at snapshot %d", snapshot)
81+
size := C.RootAtSnapshot(m.peer, C.size_t(snapshot), unsafe.Pointer(&hash[0]), C.size_t(len(hash)))
82+
if got, want := size, m.nodeSize; got != want {
83+
return nil, fmt.Errorf("failed to get root at snapshot %d, got %d bytes, expected %d", snapshot, got, want)
7784
}
7885
return hash, nil
7986
}
8087

81-
func splitSlice(slice []byte, chunkSize int) ([][]byte, error) {
88+
func splitSlice(slice []byte, numEntries, chunkSize int) ([][]byte, error) {
8289
if len(slice)%chunkSize != 0 {
8390
return nil, fmt.Errorf("slice len %d is not a multiple of chunkSize %d", len(slice), chunkSize)
8491
}
85-
numEntries := len(slice) / chunkSize
8692
ret := make([][]byte, numEntries)
8793
for i := 0; i < numEntries; i++ {
8894
start := i * chunkSize
@@ -96,33 +102,33 @@ func splitSlice(slice []byte, chunkSize int) ([][]byte, error) {
96102
func (m *CPPMerkleTree) PathToCurrentRoot(leaf uint64) ([][]byte, error) {
97103
var numEntries C.size_t
98104
entryBuffer := make([]byte, C.size_t(m.LevelCount())*m.nodeSize)
99-
success := C.PathToCurrentRoot(m.peer, C.BYTE_SLICE(&entryBuffer), &numEntries, C.size_t(leaf))
105+
success := C.PathToCurrentRoot(m.peer, C.size_t(leaf), unsafe.Pointer(&entryBuffer[0]), C.size_t(len(entryBuffer)), &numEntries)
100106
if !success {
101107
return nil, fmt.Errorf("failed to get path to current root from leaf %d", leaf)
102108
}
103-
return splitSlice(entryBuffer, int(m.nodeSize))
109+
return splitSlice(entryBuffer, int(numEntries), int(m.nodeSize))
104110
}
105111

106112
// PathToRootAtSnapshot returns an audit path to a given root for a given leaf.
107113
func (m *CPPMerkleTree) PathToRootAtSnapshot(leaf, snapshot uint64) ([][]byte, error) {
108114
var numEntries C.size_t
109115
entryBuffer := make([]byte, C.size_t(m.LevelCount())*m.nodeSize)
110-
success := C.PathToRootAtSnapshot(m.peer, C.BYTE_SLICE(&entryBuffer), &numEntries, C.size_t(leaf), C.size_t(snapshot))
116+
success := C.PathToRootAtSnapshot(m.peer, C.size_t(leaf), C.size_t(snapshot), unsafe.Pointer(&entryBuffer[0]), C.size_t(len(entryBuffer)), &numEntries)
111117
if !success {
112118
return nil, fmt.Errorf("failed to get path to root at snapshot %d from leaf %d", snapshot, leaf)
113119
}
114-
return splitSlice(entryBuffer, int(m.nodeSize))
120+
return splitSlice(entryBuffer, int(numEntries), int(m.nodeSize))
115121
}
116122

117123
// SnapshotConsistency returns a consistency proof between two given snapshots.
118124
func (m *CPPMerkleTree) SnapshotConsistency(snapshot1, snapshot2 uint64) ([][]byte, error) {
119125
var numEntries C.size_t
120126
entryBuffer := make([]byte, C.size_t(m.LevelCount())*m.nodeSize)
121-
success := C.SnapshotConsistency(m.peer, C.BYTE_SLICE(&entryBuffer), &numEntries, C.size_t(snapshot1), C.size_t(snapshot2))
127+
success := C.SnapshotConsistency(m.peer, C.size_t(snapshot1), C.size_t(snapshot2), unsafe.Pointer(&entryBuffer[0]), C.size_t(len(entryBuffer)), &numEntries)
122128
if !success {
123129
return nil, fmt.Errorf("failed to get path to snapshot consistency from %d to %d", snapshot1, snapshot2)
124130
}
125-
return splitSlice(entryBuffer, int(m.nodeSize))
131+
return splitSlice(entryBuffer, int(numEntries), int(m.nodeSize))
126132
}
127133

128134
// NewCPPMerkleTree returns a new wrapped C++ MerkleTree, using the

go/merkletree/merkle_tree_go.cc

Lines changed: 31 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#include <memory>
77
#include <vector>
88

9-
#include "_cgo_export.h"
109
#include "merkle_tree_go.h"
1110

1211
extern "C" {
@@ -22,10 +21,6 @@ static inline Sha256Hasher* H(HASHER hasher) {
2221
assert(hasher);
2322
return static_cast<Sha256Hasher*>(hasher);
2423
}
25-
static inline GoSlice* BS(BYTE_SLICE slice) {
26-
assert(slice);
27-
return static_cast<GoSlice*>(slice);
28-
}
2924

3025
HASHER NewSha256Hasher() {
3126
return new Sha256Hasher;
@@ -47,109 +42,99 @@ size_t LeafCount(TREE tree) {
4742
return MT(tree)->LeafCount();
4843
}
4944

50-
bool LeafHash(TREE tree, BYTE_SLICE out, size_t leaf) {
51-
GoSlice* slice(BS(out));
45+
size_t LeafHash(TREE tree, size_t leaf, void* buf, size_t buf_len) {
5246
const MerkleTree* t(MT(tree));
5347
const size_t nodesize(t->NodeSize());
54-
if (slice->data == NULL || slice->cap < nodesize) {
55-
return false;
48+
if (buf == NULL || buf_len < nodesize) {
49+
return 0;
5650
}
5751
const std::string& hash = t->LeafHash(leaf);
5852
assert(nodesize == hash.size());
59-
memcpy(slice->data, hash.data(), nodesize);
60-
slice->len = nodesize;
61-
return true;
53+
memcpy(buf, hash.data(), nodesize);
54+
return nodesize;
6255
}
6356

6457
size_t LevelCount(TREE tree) {
6558
const MerkleTree* t(MT(tree));
6659
return t->LevelCount();
6760
}
6861

69-
size_t AddLeaf(TREE tree, BYTE_SLICE leaf) {
70-
GoSlice* slice(BS(leaf));
62+
size_t AddLeaf(TREE tree, void* leaf, size_t leaf_len) {
7163
MerkleTree* t(MT(tree));
72-
return t->AddLeaf(std::string(static_cast<char*>(slice->data), slice->len));
64+
return t->AddLeaf(std::string(static_cast<char*>(leaf), leaf_len));
7365
}
7466

75-
size_t AddLeafHash(TREE tree, BYTE_SLICE hash) {
76-
GoSlice* slice(BS(hash));
67+
size_t AddLeafHash(TREE tree, void* hash, size_t hash_len) {
7768
MerkleTree* t(MT(tree));
7869
return t->AddLeafHash(
79-
std::string(static_cast<char*>(slice->data), slice->len));
70+
std::string(static_cast<char*>(hash), hash_len));
8071
}
8172

82-
bool CurrentRoot(TREE tree, BYTE_SLICE out) {
83-
GoSlice* slice(BS(out));
73+
size_t CurrentRoot(TREE tree, void* buf, size_t buf_len) {
8474
MerkleTree* t(MT(tree));
8575
const size_t nodesize(t->NodeSize());
86-
if (slice->data == NULL || slice->len != nodesize) {
87-
return false;
76+
if (buf == NULL || buf_len < nodesize) {
77+
return 0;
8878
}
8979
const std::string& hash = t->CurrentRoot();
9080
assert(nodesize == hash.size());
91-
memcpy(slice->data, hash.data(), nodesize);
92-
slice->len = nodesize;
93-
return true;
81+
memcpy(buf, hash.data(), nodesize);
82+
return nodesize;
9483
}
9584

96-
bool RootAtSnapshot(TREE tree, BYTE_SLICE out, size_t snapshot) {
97-
GoSlice* slice(BS(out));
85+
size_t RootAtSnapshot(TREE tree, size_t snapshot, void* buf, size_t buf_len) {
9886
MerkleTree* t(MT(tree));
9987
const size_t nodesize(t->NodeSize());
100-
if (slice->data == NULL || slice->len != nodesize) {
101-
return false;
88+
if (buf == nullptr || buf_len < nodesize) {
89+
return 0;
10290
}
10391
const std::string& hash = t->RootAtSnapshot(snapshot);
10492
assert(nodesize == hash.size());
105-
memcpy(slice->data, hash.data(), nodesize);
106-
slice->len = nodesize;
107-
return true;
93+
memcpy(buf, hash.data(), nodesize);
94+
return nodesize;
10895
}
10996

11097
// Copies the fixed-length entries from |path| into the GoSlice
11198
// pointed to by |dst|, one after the other in the same order.
11299
// |num_copied| is set to the number of entries copied.
113-
bool CopyNodesToSlice(const std::vector<std::string>& path, GoSlice* dst,
114-
size_t nodesize, size_t* num_copied) {
100+
bool CopyNodesToSlice(const std::vector<std::string>& path, void* dst,
101+
size_t dst_len, size_t nodesize, size_t* num_copied) {
115102
assert(dst);
116103
assert(num_copied);
117-
if (dst->cap < path.size() * nodesize) {
104+
if (dst_len < path.size() * nodesize) {
118105
*num_copied = 0;
119106
return false;
120107
}
121-
char* e = static_cast<char*>(dst->data);
108+
char *e(static_cast<char*>(dst));
122109
for (int i = 0; i < path.size(); ++i) {
123110
assert(nodesize == path[i].size());
124111
memcpy(e, path[i].data(), nodesize);
125112
e += nodesize;
126113
}
127-
dst->len = path.size() * nodesize;
128114
*num_copied = path.size();
129115
return true;
130116
}
131117

132-
bool PathToCurrentRoot(TREE tree, BYTE_SLICE out, size_t* num_entries,
133-
size_t leaf) {
118+
bool PathToCurrentRoot(TREE tree, size_t leaf, void* out, size_t out_len, size_t* num_entries) {
134119
MerkleTree* t(MT(tree));
135120
const std::vector<std::string> path = t->PathToCurrentRoot(leaf);
136-
return CopyNodesToSlice(path, BS(out), t->NodeSize(), num_entries);
121+
return CopyNodesToSlice(path, out, out_len, t->NodeSize(), num_entries);
137122
}
138123

139-
bool PathToRootAtSnapshot(TREE tree, BYTE_SLICE out, size_t* num_entries,
140-
size_t leaf, size_t snapshot) {
124+
bool PathToRootAtSnapshot(TREE tree, size_t leaf, size_t snapshot, void *out,
125+
size_t out_len, size_t *num_entries) {
141126
MerkleTree* t(MT(tree));
142127
const std::vector<std::string> path =
143128
t->PathToRootAtSnapshot(leaf, snapshot);
144-
return CopyNodesToSlice(path, BS(out), t->NodeSize(), num_entries);
129+
return CopyNodesToSlice(path, out, out_len, t->NodeSize(), num_entries);
145130
}
146131

147-
bool SnapshotConsistency(TREE tree, BYTE_SLICE out, size_t* num_entries,
148-
size_t snapshot1, size_t snapshot2) {
132+
bool SnapshotConsistency(TREE tree, size_t snapshot1, size_t snapshot2,
133+
void* out, size_t out_len, size_t* num_entries) {
149134
MerkleTree* t(MT(tree));
150135
const std::vector<std::string> path =
151136
t->SnapshotConsistency(snapshot1, snapshot2);
152-
return CopyNodesToSlice(path, BS(out), t->NodeSize(), num_entries);
137+
return CopyNodesToSlice(path, out, out_len, t->NodeSize(), num_entries);
153138
}
154139

155140
} // extern "C"

go/merkletree/merkle_tree_go.h

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ extern "C" {
2323
// Grumble grumble.
2424
typedef void* HASHER;
2525
typedef void* TREE;
26-
typedef void* BYTE_SLICE;
2726

2827
// Allocators & deallocators:
2928

@@ -42,30 +41,30 @@ void DeleteMerkleTree(TREE tree);
4241

4342
size_t NodeSize(TREE tree);
4443
size_t LeafCount(TREE tree);
45-
bool LeafHash(TREE tree, BYTE_SLICE out, size_t leaf);
44+
size_t LeafHash(TREE tree, size_t leaf, void* buf, size_t buf_len);
4645
size_t LevelCount(TREE tree);
47-
size_t AddLeaf(TREE tree, BYTE_SLICE leaf);
48-
size_t AddLeafHash(TREE tree, BYTE_SLICE hash);
49-
bool CurrentRoot(TREE tree, BYTE_SLICE out);
50-
bool RootAtSnapshot(TREE tree, BYTE_SLICE out, size_t snapshot);
46+
size_t AddLeaf(TREE tree, void* leaf, size_t leaf_len);
47+
size_t AddLeafHash(TREE tree, void* hash, size_t hash_len);
48+
size_t CurrentRoot(TREE tree, void *buf, size_t buf_len);
49+
size_t RootAtSnapshot(TREE tree, size_t snapshot, void* buf, size_t buf_len);
5150

5251
// |out| must contain sufficent space to hold all of the path elements
5352
// sequentially.
5453
// |num_entries| is set to the number of actual elements stored in |out|.
55-
bool PathToCurrentRoot(TREE tree, BYTE_SLICE out, size_t* num_entries,
56-
size_t leaf);
54+
bool PathToCurrentRoot(TREE tree, size_t leaf, void* out, size_t out_len,
55+
size_t* num_entries);
5756

5857
// |out| must contain sufficent space to hold all of the path elements
5958
// sequentially.
6059
// |num_entries| is set to the number of actual elements stored in |out|.
61-
bool PathToRootAtSnapshot(TREE tree, BYTE_SLICE out, size_t* num_entries,
62-
size_t leaf, size_t snapshot);
60+
bool PathToRootAtSnapshot(TREE tree, size_t leaf, size_t snapshot, void* out,
61+
size_t out_len, size_t* num_entries);
6362

6463
// |out| must contain sufficent space to hold all of the path elements
6564
// sequentially.
6665
// |num_entries| is set to the number of actual elements stored in |out|.
67-
bool SnapshotConsistency(TREE tree, BYTE_SLICE out, size_t* num_entries,
68-
size_t snapshot1, size_t snapshot2);
66+
bool SnapshotConsistency(TREE tree, size_t snapshot1, size_t snapshot2,
67+
void* out, size_t out_len, size_t* num_entries);
6968

7069
#ifdef __cplusplus
7170
}

0 commit comments

Comments
 (0)