aboutsummaryrefslogtreecommitdiff
path: root/internal/logutil/logutil.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/logutil/logutil.go')
-rw-r--r--internal/logutil/logutil.go108
1 files changed, 108 insertions, 0 deletions
diff --git a/internal/logutil/logutil.go b/internal/logutil/logutil.go
new file mode 100644
index 0000000..27c3a73
--- /dev/null
+++ b/internal/logutil/logutil.go
@@ -0,0 +1,108 @@
+// Package logutil wraps functions related to a log's Merkle tree. All log
+// queries use a context where the deadline is set to a hardcoded value.
+package logutil
+
+import (
+ "context"
+ "crypto/sha256"
+ "fmt"
+ "time"
+
+ ct "github.com/google/certificate-transparency-go"
+ "github.com/google/certificate-transparency-go/client"
+ "github.com/transparency-dev/merkle/compact"
+ "github.com/transparency-dev/merkle/rfc6962"
+ "gitlab.torproject.org/rgdd/ct/pkg/merkle"
+ "rgdd.se/silent-ct/internal/ioutil"
+)
+
+const timeout = 10 * time.Second
+
+func GetSignedTreeHead(ctx context.Context, cli client.CheckLogClient) (*ct.SignedTreeHead, error) {
+ rctx, cancel := context.WithTimeout(ctx, timeout)
+ defer cancel()
+ return cli.GetSTH(rctx)
+}
+
+func GetConsistencyProof(ctx context.Context, cli client.CheckLogClient, oldSize, newSize uint64) ([][sha256.Size]byte, error) {
+ if oldSize > newSize {
+ return nil, fmt.Errorf("old size %d is larger than new size %d", oldSize, newSize)
+ }
+ if oldSize == 0 || oldSize == newSize {
+ return [][sha256.Size]byte{}, nil
+ }
+
+ rctx, cancel := context.WithTimeout(ctx, timeout)
+ defer cancel()
+ proof, err := cli.GetSTHConsistency(rctx, oldSize, newSize)
+ if err != nil {
+ return nil, err
+ }
+ return ioutil.UnsliceHashes(proof), nil
+}
+
+func GetEntry(ctx context.Context, cli *client.LogClient, index uint64) (*ct.LeafEntry, error) {
+ rctx, cancel := context.WithTimeout(ctx, timeout)
+ defer cancel()
+
+ rsp, err := cli.GetRawEntries(rctx, int64(index), int64(index))
+ if err != nil {
+ return nil, err
+ }
+ if got, want := len(rsp.Entries), 1; got != want {
+ return nil, fmt.Errorf("too many log entries: %d (want one)", got)
+ }
+ return &rsp.Entries[0], nil
+}
+
+// GetCompactRange constructs the compact range [0, index) by doing a
+// get-proof-by-hash query to obtain the necessary tree hashes
+func GetCompactRange(ctx context.Context, cli *client.LogClient, entry *ct.LeafEntry, index uint64) (*compact.Range, error) {
+ rctx, cancel := context.WithTimeout(ctx, timeout)
+ defer cancel()
+
+ leafHash := merkle.HashLeafNode(entry.LeafInput)
+ proof, err := cli.GetProofByHash(rctx, leafHash[:], index+1)
+ if err != nil {
+ return nil, err
+ }
+ if got, want := uint64(proof.LeafIndex), index; got != want {
+ return nil, fmt.Errorf("invalid leaf index: %d (want %d)", got, want)
+ }
+ tree := ioutil.UnsliceHashes(reverse(proof.AuditPath))
+ return AppendCompactRange(tree, index, [][sha256.Size]byte{leafHash})
+}
+
+// RootHash panics if the compact range is malformed
+func RootHash(cr *compact.Range) (ret [sha256.Size]byte) {
+ rootHash, err := cr.GetRootHash(nil)
+ if err != nil {
+ panic(fmt.Sprintf("bug: compact: %v", err))
+ }
+ if got, want := len(rootHash), sha256.Size; got != want {
+ panic(fmt.Sprintf("bug: invalid root hash: size %d", got))
+ }
+ copy(ret[:], rootHash[:])
+ return
+}
+
+// AppendCompactRange appends a list of leaf hashes to the compact range [0, size)
+func AppendCompactRange(tree [][sha256.Size]byte, size uint64, pending [][sha256.Size]byte) (*compact.Range, error) {
+ rf := compact.RangeFactory{Hash: rfc6962.DefaultHasher.HashChildren}
+ cr, err := rf.NewRange(0, size, ioutil.SliceHashes(tree))
+ if err != nil {
+ return nil, fmt.Errorf("compact: %v", err)
+ }
+ for _, leafHash := range pending {
+ dst := leafHash
+ cr.Append(dst[:], nil)
+ }
+ return cr, nil
+}
+
+func reverse(hashes [][]byte) (ret [][]byte) {
+ for i := len(hashes) - 1; i >= 0; i-- {
+ ret = append(ret, hashes[i])
+ }
+ return
+}