A transparent, highly scalable and cryptographically verifiable data store.
[!NOTE]
Trillian is in maintenance mode.
The next generation of transparency logs uses Tiled APIs
and are better supported by Trillian Tessera.
We recommend that any new log operators first try Tessera.Community contributions to Trillian are still welcome, but please file an issue and/or swing by the Slack first for discussion!
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 the
following:
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 an 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.
The Trillian codebase is stable and is used in production by multiple
organizations, including many large-scale
Certificate Transparency log
operators.
Given this, we do not plan to add any new features to this version of Trillian,
and will try to avoid any further incompatible code and schema changes but
cannot guarantee that they will never be necessary.
The current state of feature implementation is recorded in the
Feature implementation matrix.
To build and test Trillian you need:
To run many of the tests (and production deployment) you need:
Note that this repository uses Go modules to manage dependencies; Go will fetch
and install them automatically upon build/test.
To fetch the code, dependencies, and build Trillian, run the following:
git clone https://github.com/google/trillian.git
cd trillian
go build ./...
To build slimmer Trillian binaries that only include the storage and quota
implementations that you need, consider specifying
build tags.
To build and run tests, use:
go test ./...
The repository also includes multi-process integration tests, described in the
Integration Tests section below.
To run Trillian’s integration tests you need to have an instance of MySQL
running and configured to:
mysql --host=127.0.0.1
--port=3306
connects OK)root
userYou can then set up the expected tables in atest
database like so:
./scripts/resetdb.sh
Warning: about to destroy and reset database 'test'
Are you sure? y
> Resetting DB...
> Reset Complete
Trillian includes an integration test suite to confirm basic end-to-end
functionality, which can be run with:
./integration/integration_test.sh
This runs a multi-process test:
You can find instructions on how to deploy Trillian in deployment
and examples/deployment directories.
Developers who want to make changes to the Trillian codebase need some
additional dependencies and tools, described in the following sections. The
Cloud Build configuration and the scripts it depends on are
also a useful reference for the required tools and scripts, as it may be more
up-to-date than this document.
Anyone wanting to add a new storage and/or quota implementation should
understand how Trillian uses build tags.
Some of the Trillian Go code is autogenerated from other files:
fmt.Stringer
go get
golang.org/x/tools/cmd/stringer
).Re-generating mock or protobuffer files is only needed if you’re changing
the original files. The recommended way to do this is by using the Docker
image used by the Cloud Build:
docker build -f ./integration/cloudbuild/testbase/Dockerfile -t trillian-builder .
docker run -it --mount type=bind,src="$(pwd)",target=/src trillian-builder /bin/bash -c "cd /src; ./scripts/install_deps.sh; go generate -x ./..."
These commands first create a docker image from the Dockerfile in this repo, and
then launch a container based on this image with the local directory mounted. The
correct versions of the tools are determined using the go.mod
file in this repo,
and these tools are installed. Finally, all of the generated files are regenerated
and Docker exits.
Alternatively, you can install the prerequisites locally:
a series of tools, using go install
to ensure that the versions are
compatible and tested:
cd $(go list -f '{{ .Dir }}' github.com/google/trillian); \
go install github.com/golang/mock/mockgen; \
go install google.golang.org/protobuf/proto; \
go install google.golang.org/protobuf/cmd/protoc-gen-go; \
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc; \
go install github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc; \
go install golang.org/x/tools/cmd/stringer
and run the following:
go generate -x ./... # hunts for //go:generate comments and runs them
The Trillian codebase uses go.mod to declare fixed versions of its dependencies.
With Go modules, updating a dependency simply involves running go get
:
go get package/path # Fetch the latest published version
go get package/path@X.Y.Z # Fetch a specific published version
go get package/path@HEAD # Fetch the latest commit
To update ALL dependencies to the latest version run go get -u
.
Be warned however, that this may undo any selected versions that resolve issues in other non-module repos.
While running go build
and go test
, go will add any ambiguous transitive dependencies to go.mod
To clean these up run:
go mod tidy
The scripts/presubmit.sh
script runs various tools
and tests over the codebase.
go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.1
./scripts/presubmit.sh
golangci-lint run
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:
In either case, Trillian’s key transparency property is that cryptographic
proofs of inclusion/consistency are available for data items added to the
service.
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:
This is
described in more detail in a separate document.
General
design considerations for transparent Log applications
are also discussed separately.
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 theGetLeavesByRange
returns leaf information for particular leaves,QueueLeaf
requests inclusion of the specified item into the log.AddSequencedLeaves
requests the inclusion ofGetInclusionProof
, GetInclusionProofByHash
and GetConsistencyProof
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.
(Note that each of the components in this diagram can be
distributed,
for scalability and resilience.)
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.