22
33# siglog
44
5- A Rust implementation of a [ Tessera] ( https://github.com/transparency-dev/tessera ) -compatible transparency log server for package distribution systems .
5+ A Rust transparency log server for package distribution systems, with [ Tessera] ( https://github.com/transparency-dev/tessera ) and [ Rekor v2 ] ( https://github.com/sigstore/rekor-tiles ) HTTP API modes .
66
77This implementation follows the [ C2SP tlog-tiles] ( https://c2sp.org/tlog-tiles ) specification and provides an append-only Merkle tree with cryptographic guarantees that all users see the same data.
88
@@ -71,6 +71,7 @@ cargo build --release
7171
7272| Variable | Description | Default |
7373| ----------| -------------| ---------|
74+ | ` LOG_MODE ` | API mode: ` tessera ` or ` rekor ` (` --mode ` ) | ` tessera ` |
7475| ` LISTEN_ADDR ` | Server listen address | ` 0.0.0.0:8080 ` |
7576| ` DATABASE_URL ` | Database connection string | ` sqlite:./siglog.db?mode=rwc ` |
7677| ` LOG_ORIGIN ` | Log origin identifier | Required |
@@ -82,8 +83,8 @@ cargo build --release
8283| ` S3_SECRET_KEY ` | S3 secret key | - |
8384| ` S3_ENDPOINT ` | S3 endpoint URL | - |
8485| ` S3_REGION ` | S3 region | ` auto ` |
85- | ` API_KEY ` | Bearer token required for ` /add ` writes | Required unless ` ALLOW_PUBLIC_WRITES=true ` |
86- | ` ALLOW_PUBLIC_WRITES ` | Allow unauthenticated ` /add ` writes for local development | ` false ` |
86+ | ` API_KEY ` | Bearer token required for write requests in either mode | Required unless ` ALLOW_PUBLIC_WRITES=true ` |
87+ | ` ALLOW_PUBLIC_WRITES ` | Allow unauthenticated writes for local development | ` false ` |
8788| ` CHECKPOINT_INTERVAL ` | Checkpoint frequency (seconds) | ` 1 ` |
8889| ` BATCH_MAX_SIZE ` | Max entries per batch | ` 256 ` |
8990| ` BATCH_MAX_AGE_MS ` | Max batch age (ms) | ` 1000 ` |
@@ -219,7 +220,80 @@ Response (on success): The witness's cosignature line.
219220
220221## API Reference
221222
222- ### Log Server Endpoints
223+ ### Choosing an API mode
224+
225+ ``` bash
226+ # Existing raw-entry API (default)
227+ ./target/release/siglog --mode tessera
228+
229+ # Rekor v2 HTTP/JSON API; use a NEW database and tile storage directory
230+ ./target/release/siglog --mode rekor \
231+ --database-url ' sqlite:./rekor.db?mode=rwc' --fs-root ./rekor-tiles
232+ ```
233+
234+ Both commands also require the signing key, origin, and write-authentication configuration described above.
235+ The selected mode is persisted in the database; startup rejects a different mode.
236+ Existing non-empty, unmarked databases are treated as Tessera logs. Use separate
237+ storage, databases, and log identities for separate logs—do not mix their writers.
238+
239+ Rekor mode exposes:
240+
241+ | Endpoint | Method | Description |
242+ | ----------| --------| -------------|
243+ | ` /api/v2/log/entries ` | POST | Verify and integrate a hashedrekord v0.0.2 entry |
244+ | ` /api/v2/checkpoint ` | GET | Latest signed checkpoint |
245+ | ` /api/v2/tile/{level}/{index} ` | GET | Hash tile, including partial tiles |
246+ | ` /api/v2/tile/entries/{index} ` | GET | Entry bundle, including partial bundles |
247+ | ` /health ` , ` /ready ` | GET | Health and readiness |
248+
249+ ` /add ` is ** not exposed** in Rekor mode. Existing explorer/package-monitor clients
250+ that use the unprefixed API should continue using Tessera mode. Generic tile readers
251+ can use ` /api/v2/ ` as their read base URL in Rekor mode.
252+
253+ The submission schema follows [ Rekor v2] ( https://github.com/sigstore/rekor-tiles/blob/v2.3.0/api/proto/rekor/v2/entry.proto ) :
254+
255+ ``` json
256+ {
257+ "hashedRekordRequestV002" : {
258+ "digest" : " BASE64_ARTIFACT_SHA256" ,
259+ "signature" : {
260+ "content" : " BASE64_DER_ECDSA_SIGNATURE" ,
261+ "verifier" : {
262+ "publicKey" : {"rawBytes" : " BASE64_DER_SPKI_PUBLIC_KEY" },
263+ "keyDetails" : " PKIX_ECDSA_P256_SHA_256"
264+ }
265+ }
266+ }
267+ }
268+ ```
269+
270+ Use ` Content-Type: application/json ` and ` Authorization: Bearer <API_KEY> ` .
271+ Exactly one ` publicKey ` or ` x509Certificate ` (DER, base64-encoded ` rawBytes ` ) is required.
272+ Supported signature algorithms are Ed25519ph/SHA-512 (` PKIX_ED25519_PH ` , empty
273+ context), ECDSA P-256/SHA-256, P-384/SHA-384, P-521/SHA-512 and RSA PKCS #1 v1.5
274+ SHA-256 with 2048/3072/4096-bit keys. Ed25519ph takes the artifact's SHA-512 digest;
275+ pure Ed25519 signatures over that digest are not interchangeable.
276+ Artifact signatures and key/algorithm agreement are verified before sequencing.
277+ Certificate trust/identity policy remains the client's responsibility, as in Rekor.
278+ RSA-PSS, deprecated DSSE submissions, and gRPC transport are not implemented.
279+
280+ A successful write returns HTTP ** 201** and a Sigstore ` TransparencyLogEntry ` :
281+ canonicalized body, log ID, kind/version, and inclusion proof against a ** published,
282+ signed checkpoint** . Protobuf JSON integer fields are strings and byte fields are
283+ base64. No v1 signed-entry timestamp/inclusion promise is issued.
284+ The log ID is the full SHA-256 note-key hash, matching rekor-tiles v2.3.0.
285+
286+ Requests wait up to 30 seconds for sequencing, integration, and checkpoint publication
287+ (including configured witnesses). A 504 does ** not** undo a queued entry.
288+ Exact canonical entries are deduplicated permanently and atomically in the database,
289+ including concurrent retries, pending entries, and retries after restarts. A duplicate
290+ returns HTTP ** 409** , gRPC JSON code ** 6** , and an ` x-log-index ` header with the original
291+ index. This is not an inclusion promise: that entry may still await integration.
292+ Different signatures or verification material produce different entries even for the
293+ same artifact. Tessera mode still appends every submission.
294+ Request bodies and canonical entries are each limited to 65,535 bytes.
295+
296+ ### Tessera Log Server Endpoints
223297
224298| Endpoint | Method | Description |
225299| ----------| --------| -------------|
@@ -387,6 +461,22 @@ Clients can verify entries against the transparency log:
3874614. For a specific entry, fetch the inclusion proof
3884625. Verify the proof against the checkpoint root hash
389463
464+ ### Rekor interoperability checks
465+
466+ ` ` ` bash
467+ cargo test --workspace
468+ cargo build --bin siglog
469+ (cd rekor-conformance && go test -v)
470+ ```
471+
472+ The Go test requires Go 1.25.8+ (or automatic Go toolchain downloads). It launches an
473+ isolated local server and uses the upstream rekor-tiles v2.3.0 writer and verifier
474+ to check all supported signing algorithms, public keys and certificates, canonical
475+ entry reconstruction, Ed25519ph signatures, duplicate responses, and inclusion proofs
476+ across a full tile boundary. CI also checks concurrent deduplication and rollback on
477+ SQLite and PostgreSQL; locally, set ` SIGLOG_TEST_POSTGRES_URL ` to a dedicated empty
478+ PostgreSQL database to run that check.
479+
390480## License
391481
392482BSD-3-Clause. See [ LICENSE] ( LICENSE ) for details.
0 commit comments