Trillian implements a Merkle tree whose contents are served from a data storage layer, to allow scalability to extremely large trees.
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
client Embed formatting into RetriableError (#1355) Nov 20, 2018
cmd updatetree: Support changing TreeType (#1354) Nov 21, 2018
crypto Re-generate .pb.go files with new protoc-gen-go (#1359) Nov 28, 2018
docs [Map] Add revision parameter to SetLeaves (#1370) Dec 10, 2018
examples Re-generate .pb.go files with new protoc-gen-go (#1359) Nov 28, 2018
extension Move election code to a separate package (#1151) May 25, 2018
integration [Map] Add revision parameter to SetLeaves (#1370) Dec 10, 2018
log Move compact Merkle tree to compact package (#1339) Oct 31, 2018
merkle Move uncommon common functions to uncommon place (#1371) Dec 10, 2018
monitoring Add tests for ExecutePass failing in log_operation_manager_test.go Oct 8, 2018
quota Run formatter on proto files Dec 10, 2018
scripts Create user for pg testing (#1348) Nov 19, 2018
server [Map] Add revision parameter to SetLeaves (#1370) Dec 10, 2018
storage Run formatter on proto files Dec 10, 2018
testdata Ensure that dump_tree output doesn't change (#760) Jul 28, 2017
testonly [Map] Add revision parameter to SetLeaves (#1370) Dec 10, 2018
trees Add auto-generated String() method to trees.OpType Sep 13, 2018
types Better tests for types package (#1070) Mar 26, 2018
util [election2] Add etcd client creation wrapper (#1289) Sep 17, 2018
vendor/github.com Delete broken symlink: vendor/github.com/coreos/etcd/cmd/tools Nov 16, 2018
.gitignore maphammer: allow replay of journalled requests May 23, 2018
.travis.yml Fix Travis check for uncommitted diffs in generated files Dec 7, 2018
AUTHORS Create user for pg testing (#1348) Nov 19, 2018
CHANGELOG.md Run CHANGELOG.md through Markdown formatter Dec 7, 2018
CONTRIBUTING.md Initial commit to add some basics to repo May 31, 2016
CONTRIBUTORS Create user for pg testing (#1348) Nov 19, 2018
Dockerfile.db Add Docker build files (#607) May 23, 2017
LICENSE Squashed 'vendor/github.com/coreos/etcd/' content from commit 44a017e… Apr 21, 2017
PULL_REQUEST_TEMPLATE.md Pull Request Template (#1360) Nov 29, 2018
README.md docs: use Unicode en dash Dec 5, 2018
cloudbuild.yaml Create Cloud Build equivalent of examples/deployment/kubernetes/deplo… Nov 16, 2018
cloudbuild_tag.yaml Add db_server Docker image to cloudbuild_tag.yaml Nov 14, 2018
gen.go Generate Markdown documentation for APIs Sep 27, 2018
gometalinter.json Lint check looking for use of forked proto package (#1016) Feb 23, 2018
trillian.pb.go Re-generate .pb.go files with new protoc-gen-go (#1359) Nov 28, 2018
trillian.proto Run formatter on proto files Dec 10, 2018
trillian_admin_api.pb.go Re-generate .pb.go files with new protoc-gen-go (#1359) Nov 28, 2018
trillian_admin_api.pb.gw.go Re-generate grpc-gateway code Dec 7, 2018
trillian_admin_api.proto Run formatter on proto files Dec 10, 2018
trillian_log_api.pb.go Re-generate .pb.go files with new protoc-gen-go (#1359) Nov 28, 2018
trillian_log_api.pb.gw.go Re-generate grpc-gateway code Dec 7, 2018
trillian_log_api.proto Run formatter on proto files Dec 10, 2018
trillian_log_sequencer_api.pb.go Re-generate .pb.go files with new protoc-gen-go (#1359) Nov 28, 2018
trillian_log_sequencer_api.proto Run formatter on proto files Dec 10, 2018
trillian_map_api.pb.go [Map] Add revision parameter to SetLeaves (#1370) Dec 10, 2018
trillian_map_api.pb.gw.go Re-generate grpc-gateway code Dec 7, 2018
trillian_map_api.proto [Map] Add revision parameter to SetLeaves (#1370) Dec 10, 2018

README.md

Trillian: General Transparency

Build Status Go Report Card GoDoc Slack Status

Overview

Trillian is an implementation of the concepts described in the Verifiable Data Structures white paper, which in turn is an extension and generalisation of the ideas which underpin Certificate Transparency.

Trillian implements a Merkle tree whose contents are served from a data storage layer, to allow scalability to extremely large trees. On top of this Merkle tree, Trillian provides two modes:

  • An append-only Log mode, analogous to the original Certificate Transparency logs. In this mode, the Merkle tree is effectively filled up from the left, giving a dense Merkle tree.
  • An experimental Map mode that allows transparent storage of arbitrary key:value pairs derived from the contents of a source Log; this is also known as a log-backed map. In this mode, the key's hash is used to designate a particular leaf of a deep Merkle tree – sufficiently deep that filled leaves are vastly outnumbered by unfilled leaves, giving a sparse Merkle tree. (A Trillian Map is an unordered map; it does not allow enumeration of the Map's keys.)

Note that Trillian requires particular applications to provide their own personalities on top of the core transparent data store functionality.

Certificate Transparency (CT) is the most well-known and widely deployed transparency application, and a implementation of CT as a Trillian personality is available in the certificate-transparency-go repo.

Other examples of Trillian personalities are available in the trillian-examples repo.

Support

Using the Code

WARNING: The Trillian codebase is still under development, but the Log mode is now being used in production by several organizations. We will try to avoid any further incompatible code and schema changes but cannot guarantee that they will never be necessary.

To build and test Trillian you need:

  • Go 1.9 or later.

To run many of the tests (and production deployment) you need:

Use the standard Go tools to install other dependencies.

go get github.com/google/trillian
cd $GOPATH/src/github.com/google/trillian
go get -t -u -v ./...

To build and run tests, use:

go test ./...

Note that go seems to sometimes fail to fetch or update all dependencies (as of v1.10.2), so you may need to manually fetch missing ones, or update all Go source with:

go get -u -v all

The repository also includes multi-process integration tests, described in the Integration Tests section below.

MySQL Setup

To run Trillian's integration tests you need to have an instance of MySQL running and configured to:

  • listen on the standard MySQL port 3306 (so mysql --host=127.0.0.1 --port=3306 connects OK)
  • not require a password for the root user

You can then set up the expected tables in a test database like so:

./scripts/resetdb.sh
Warning: about to destroy and reset database 'test'
Are you sure? y
> Resetting DB...
> Reset Complete

If you are working with the Trillian Map, you will probably need to increase the MySQL maximum connection count:

% mysql -u root
MySQL> SET GLOBAL max_connections = 1000;

Integration Tests

Trillian includes an integration test suite to confirm basic end-to-end functionality, which can be run with:

./integration/integration_test.sh

This runs two multi-process tests:

  • A test that starts a Trillian server in Log mode, together with a signer, logs many leaves, and checks they are integrated correctly.
  • A test that starts a Trillian server in Map mode, sets various key:value pairs and checks they can be retrieved.

Working on the Code

Developers who want to make changes to the Trillian codebase need some additional dependencies and tools, described in the following sections. The Travis configuration for the codebase is also useful reference for the required tools and scripts, as it may be more up-to-date than this document.

Rebuilding Generated Code

Some of the Trillian Go code is autogenerated from other files:

  • gRPC message structures are originally provided as protocol buffer message definitions.
  • Some unit tests use mock implementations of interfaces; these are created from the real implementations by GoMock.
  • Some enums have string-conversion methods (satisfying the fmt.Stringer interface) created using the stringer tool (go get golang.org/x/tools/cmd/stringer).

Re-generating mock or protobuffer files is only needed if you're changing the original files; if you do, you'll need to install the prerequisites:

and run the following:

go generate -x ./...  # hunts for //go:generate comments and runs them

Updating Vendor Code

The Trillian codebase includes a couple of external projects under the vendor/ subdirectory, to ensure that builds use a fixed version (typically because the upstream repository does not guarantee back-compatibility between the tip master branch and the current stable release). These external codebases are included as Git subtrees.

To update the code in one of these subtrees, perform steps like:

# Add master repo for upstream code as a Git remote.
git remote add vendor-xyzzy https://github.com/orgname/xyzzy
# Pull the updated code for the desired version tag from the remote, dropping history.
# Trailing / in prefix is needed.
git subtree pull --squash --prefix=vendor/github.com/orgname/xyzzy/ vendor-xyzzy vX.Y.Z

If new vendor/ subtree is required, perform steps similar to:

# Add master repo for upstream code as a Git remote.
git remote add vendor-xyzzy https://github.com/orgname/xyzzy
# Pull the desired version of the code in, dropping history.
# Trailing / in --prefix is needed.
git subtree add --squash --prefix=vendor/github.com/orgname/xyzzy/ vendor-xyzzy vX.Y.Z

Running Codebase Checks

The scripts/presubmit.sh script runs various tools and tests over the codebase.

# Install gometalinter and all linters
go get -u github.com/alecthomas/gometalinter
gometalinter --install

# Run code generation, build, test and linters
./scripts/presubmit.sh

# Or just run the linters alone:
gometalinter --config=gometalinter.json ./...

Design

Design Overview

Trillian is primarily implemented as a gRPC service; this service receives get/set requests over gRPC and retrieves the corresponding Merkle tree data from a separate storage layer (currently using MySQL), ensuring that the cryptographic properties of the tree are preserved along the way.

The Trillian service is multi-tenanted – a single Trillian installation can support multiple Merkle trees in parallel, distinguished by their TreeId – and each tree operates in one of two modes:

  • Log mode: an append-only collection of items; this has two sub-modes:
    • normal Log mode, where the Trillian service assigns sequence numbers to new tree entries as they arrive
    • 'preordered' Log mode, where the unique sequence number for entries in the Merkle tree is externally specified
  • Map mode: a collection of key:value pairs.

In either case, Trillian's key transparency property is that cryptographic proofs of inclusion/consistency are available for data items added to the service.

Personalities

To build a complete transparent application, the Trillian core service needs to be paired with additional code, known as a personality, that provides functionality that is specific to the particular application.

In particular, the personality is responsible for:

  • Admission Criteria – ensuring that submissions comply with the overall purpose of the application.
  • Canonicalization – ensuring that equivalent versions of the same data get the same canonical identifier, so they can be de-duplicated by the Trillian core service.
  • External Interface – providing an API for external users, including any practical constraints (ACLs, load-balancing, DoS protection, etc.)

This is described in more detail in a separate document. General design considerations for transparent Log applications are also discussed seperately.

Log Mode

When running in Log mode, Trillian provides a gRPC API whose operations are similar to those available for Certificate Transparency logs (cf. RFC 6962). These include:

  • GetLatestSignedLogRoot returns information about the current root of the Merkle tree for the log, including the tree size, hash value, timestamp and signature.
  • GetLeavesByHash, GetLeavesByIndex and GetLeavesByRange return leaf information for particular leaves, specified either by their hash value or index in the log.
  • QueueLeaves requests inclusion of specified items into the log.
    • For a pre-ordered log, AddSequencedLeaves requests the inclusion of specified items into the log at specified places in the tree.
  • GetInclusionProof, GetInclusionProofByHash and GetConsistencyProof return inclusion and consistency proof data.

In Log mode (whether normal or pre-ordered), Trillian includes an additional Signer component; this component periodically processes pending items and adds them to the Merkle tree, creating a new signed tree head as a result.

Log components

(Note that each of the components in this diagram can be distributed, for scalability and resilience.)

Map Mode

WARNING: Trillian Map mode is experimental and under development; it should not be relied on for a production service (yet).

Trillian in Map mode can be thought of as providing a key:value store for values derived from a data source (normally a Trillian Log), together with cryptographic transparency guarantees for that data.

When running in Map mode, Trillian provides a straightforward gRPC API with the following available operations:

  • SetLeaves requests inclusion of specified key:value pairs into the Map; these will appear as the next revision of the Map, with a new tree head for that revision.
  • GetSignedMapRoot returns information about the current root of the Merkle tree representing the Map, including a revision , hash value, timestamp and signature.
    • A variant allows queries of the tree root at a specified historical revision.
  • GetLeaves returns leaf information for a specified set of key values, optionally as of a particular revision. The returned leaf information also includes inclusion proof data.

Map components

Logged Map

As a stand-alone component, it is not possible to reliably monitor or audit a Trillian Map instance; key:value pairs can be modified and subsequently reset without anyone noticing.

A future plan to deal with this is to create a Logged Map, which combines a Trillian Map with a Trillian Log so that all published revisions of the Map have their signed tree head data appended to the corresponding Map.

The mapping between the source Log data and the key:value data stored in the Map is application-specific, and so is implemented as a Trillian personality. This allows for wide flexibility in the mapping function:

  • The simplest example is a Log that holds a journal of pending mutations to the key:value data; the mapping function here simply applies a batch of mutations.
  • A more sophisticated example might log entries that are independently of interest (e.g. Web PKI certificates) and apply a more complex mapping function (e.g. map from domain name to public key for the domains covered by a certificate).

Log-Backed Map

Use Cases

Certificate Transparency Log

The most obvious application for Trillian in Log mode is to provide a Certificate Transparency (RFC 6962) Log. To do this, the CT Log personality needs to include all of the certificate-specific processing – in particular, checking that an item that has been suggested for inclusion is indeed a valid certificate that chains to an accepted root.

Verifiable Log-Backed Map

One useful application for Trillian in Map mode is to provide a verifiable log-backed map, as described in the Verifiable Data Structures white paper (which uses the term 'log-backed map'). To do this, a mapper personality would monitor the additions of entries to a Log, potentially external, and would write some kind of corresponding key:value data to a Trillian Map.

Clients of the log-backed map are then able to verify that the entries in the Map they are shown are also seen by anyone auditing the Log for correct operation, which in turn allows the client to trust the key/value pairs returned by the Map.

A concrete example of this might be a log-backed map that monitors a Certificate Transparency Log and builds a corresponding Map from domain names to the set of certificates associated with that domain.

The following table summarizes properties of data structures laid in the Verifiable Data Structures white paper. "Efficiently" means that a client can and should perform this validation themselves. "Full audit" means that to validate correctly, a client would need to download the entire dataset, and is something that in practice we expect a small number of dedicated auditors to perform, rather than being done by each client.

Verifiable Log Verifiable Map Verifiable Log-Backed Map
Prove inclusion of value Yes, efficiently Yes, efficiently Yes, efficiently
Prove non-inclusion of value Impractical Yes, efficiently Yes, efficiently
Retrieve provable value for key Impractical Yes, efficiently Yes, efficiently
Retrieve provable current value for key Impractical No Yes, efficiently
Prove append-only Yes, efficiently No Yes, efficiently [1].
Enumerate all entries Yes, by full audit Yes, by full audit Yes, by full audit
Prove correct operation Yes, efficiently No Yes, by full audit
Enable detection of split-view Yes, efficiently Yes, efficiently Yes, efficiently
  • [1] -- although full audit is required to verify complete correct operation