Top Related Projects
Auditing for TLS certificates (Go code)
Notary is a project that allows anyone to have trust over arbitrary collections of data
Code signing and transparency for containers and binaries
Quick Overview
Trillian is a transparent, highly scalable and cryptographically verifiable data store developed by Google. It is designed to be a general-purpose transparent log or Merkle tree storage system, which can be used for various applications such as Certificate Transparency logs, tamper-evident logging, and verifiable data structures.
Pros
- Highly scalable and efficient, capable of handling large-scale data storage and verification
- Provides strong security guarantees through cryptographic verification
- Flexible and adaptable for various use cases beyond just Certificate Transparency
- Open-source project with active development and community support
Cons
- Complex system that may require significant learning curve for implementation
- Limited documentation for some advanced features or use cases
- Requires careful configuration and management for optimal performance
- May be overkill for smaller-scale projects or simpler logging needs
Code Examples
- Creating a new log:
logID, err := client.CreateTree(ctx, &trillian.CreateTreeRequest{
Tree: &trillian.Tree{
TreeState: trillian.TreeState_ACTIVE,
TreeType: trillian.TreeType_LOG,
HashStrategy: trillian.HashStrategy_RFC6962_SHA256,
HashAlgorithm: sigpb.DigitallySigned_SHA256,
SignatureAlgorithm: sigpb.DigitallySigned_ECDSA,
DisplayName: "My Log",
Description: "A sample log",
},
})
- Adding a leaf to the log:
leaf := []byte("Hello, Trillian!")
req := &trillian.QueueLeafRequest{
LogId: logID,
Leaf: &trillian.LogLeaf{
LeafValue: leaf,
},
}
_, err := client.QueueLeaf(ctx, req)
- Getting a consistency proof:
proof, err := client.GetConsistencyProof(ctx, &trillian.GetConsistencyProofRequest{
LogId: logID,
FirstTreeSize: 1,
SecondTreeSize: 2,
})
Getting Started
To get started with Trillian, follow these steps:
- Install Go (version 1.13 or later)
- Clone the repository:
git clone https://github.com/google/trillian.git
- Build the project:
cd trillian go build ./...
- Run the tests:
go test ./...
- Set up a database (MySQL or MariaDB) and configure it in the config file
- Run the Trillian components (Log Server, Log Signer, etc.) using the provided binaries or Docker images
For more detailed instructions and configuration options, refer to the project's documentation and examples in the repository.
Competitor Comparisons
Auditing for TLS certificates (Go code)
Pros of certificate-transparency-go
- Specifically designed for Certificate Transparency (CT) logs
- Includes tools for CT log operators and auditors
- Provides a complete implementation of the CT protocol
Cons of certificate-transparency-go
- Limited to Certificate Transparency use cases
- May require more setup for non-CT applications
- Less flexible for general-purpose verifiable data structures
Code Comparison
certificate-transparency-go:
type LogClient struct {
uri string
client *http.Client
}
func (c *LogClient) GetSTH() (*ct.SignedTreeHead, error) {
// Implementation specific to CT logs
}
Trillian:
type TrillianLogClient struct {
client trillian.TrillianLogClient
}
func (c *TrillianLogClient) GetLatestSignedLogRoot(ctx context.Context) (*trillian.SignedLogRoot, error) {
// More generic implementation for various log types
}
Both repositories are maintained by Google and focus on verifiable data structures. Trillian is a more general-purpose solution for creating and managing verifiable logs and maps, while certificate-transparency-go is tailored specifically for Certificate Transparency logs. Trillian offers greater flexibility and can be used for a wider range of applications, whereas certificate-transparency-go provides a complete, ready-to-use implementation for CT logs.
Notary is a project that allows anyone to have trust over arbitrary collections of data
Pros of Notary
- Focused on secure content distribution and software supply chain integrity
- Provides a comprehensive trust system with role-based access control
- Integrates well with Docker and container ecosystems
Cons of Notary
- More complex setup and configuration compared to Trillian
- Limited to specific use cases in content trust and distribution
- Smaller community and fewer integrations outside of container ecosystems
Code Comparison
Notary (Go):
func (tg *tufGetter) getTargets(role string) (*data.SignedTargets, error) {
targetsPath := fmt.Sprintf("/%s.%s", role, "json")
raw, err := tg.download(targetsPath, "targets")
if err != nil {
return nil, err
}
// ... (additional processing)
}
Trillian (Go):
func (t *Tree) GetLeavesByIndex(ctx context.Context, treeRevision int64, leafIndices []int64) ([]*trillian.LogLeaf, error) {
tx, err := t.beginReadOnlyTreeTX(ctx, treeRevision)
if err != nil {
return nil, err
}
defer tx.Close()
// ... (additional processing)
}
Both projects use Go and focus on secure data management, but Notary is more specialized for content trust, while Trillian provides a more general-purpose verifiable data structure.
Code signing and transparency for containers and binaries
Pros of Cosign
- Focused specifically on container image signing and verification
- Simpler setup and usage for container-centric workflows
- Integrates well with existing container registries and CI/CD pipelines
Cons of Cosign
- More limited in scope compared to Trillian's general-purpose transparency log
- Less suitable for large-scale, distributed verification scenarios
- Lacks some of the advanced cryptographic features of Trillian
Code Comparison
Cosign (signing a container image):
cosign sign -key cosign.key my-registry.example.com/my-image:tag
Trillian (adding an entry to a log):
client := trillian.NewTrillianLogClient(conn)
resp, err := client.QueueLeaf(ctx, &trillian.QueueLeafRequest{
LogId: logID,
Leaf: &trillian.LogLeaf{LeafValue: []byte("example data")},
})
Both projects aim to enhance security and transparency, but Cosign is more specialized for container workflows, while Trillian offers a broader, more flexible approach to creating verifiable data structures.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Trillian: General Transparency
[!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!
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 the following:
- 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.
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.
Support
- Mailing list: https://groups.google.com/forum/#!forum/trillian-transparency
- Slack: https://transparency-dev.slack.com/ (invitation)
Using the Code
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:
- Go 1.23 or later (go 1.23 matches cloudbuild, and is preferred for developers that will be submitting PRs to this project).
To run many of the tests (and production deployment) you need:
- MySQL or MariaDB to provide the data storage layer; see the MySQL Setup section.
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.
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
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 a multi-process test:
- A test that starts a Trillian server in Log mode, together with a signer, logs many leaves, and checks they are integrated correctly.
Deployment
You can find instructions on how to deploy Trillian in deployment and examples/deployment directories.
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 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.
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. See also, https://grpc.io/docs/protoc-installation/.
- 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. 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
Updating Dependencies
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
Running Codebase Checks
The scripts/presubmit.sh
script runs various tools
and tests over the codebase.
Install golangci-lint.
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6
Run code generation, build, test and linters
./scripts/presubmit.sh
Or just run the linters alone
golangci-lint run
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
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 separately.
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.GetLeavesByRange
returns leaf information for particular leaves, specified by their index in the log.QueueLeaf
requests inclusion of the specified item into the log.- For a pre-ordered log,
AddSequencedLeaves
requests the inclusion of specified items into the log at specified places in the tree.
- For a pre-ordered log,
GetInclusionProof
,GetInclusionProofByHash
andGetConsistencyProof
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.
(Note that each of the components in this diagram can be distributed, for scalability and resilience.)
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.
Top Related Projects
Auditing for TLS certificates (Go code)
Notary is a project that allows anyone to have trust over arbitrary collections of data
Code signing and transparency for containers and binaries
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot