UCANLOG is a Go library for building transparent append-only log services using Tessera with capability-based access control via UCANs and user-owned storage via Storacha.
Status: Experimental. Use at your own risk.
UCANLOG forms the foundation for "Proof-as-a-Service" — user-owned append-only logs that serve as verifiable evidence for chains of custody, provenance, credential issuance, and key agreement protocols. Each record is a public commitment to public or private data via cryptographic hashing.
It uses the same tamper-proof system as the Sigstore Certificate Authority, but adds:
- User-controlled decentralized authorization — UCAN delegation chains; write access revocable instantly
- User-controlled decentralized storage — data lives on the IPFS network; fully portable
See SEQUENCE DIAGRAM for the full data flow.
go get github.com/relves/ucanlogstoreManager := sqlite.NewStoreManager("./data")
defer storeManager.CloseAll()
tlogMgr, err := tlog.NewDelegatedManager(tlog.DelegatedManagerConfig{
BasePath: "./data",
ServiceSigner: serviceSigner,
// ...
})
logService := log.NewLogServiceWithConfig(log.LogServiceConfig{
TlogManager: tlogMgr,
StoreManager: storeManager,
ServiceDID: serviceSigner.DID().String(),
})
srv, err := server.NewServer(
server.WithSigner(serviceSigner),
server.WithLogService(logService),
server.WithStoreManager(storeManager),
)All write operations are invoked over UCAN RPC (POST /). Every request is independently authenticated — no server-side sessions.
Creates a new transparent log. The space DID from the delegation becomes the log identity.
Caveats: delegation (base64 UCAN)
Returns: { logId, tree_size: 0 }
Appends data to an existing log.
Caveats:
| Field | Required | Description |
|---|---|---|
data |
Yes | Base64-encoded data to append |
delegation |
Yes | Base64-encoded UCAN delegation |
Returns:
| Field | Description |
|---|---|
index |
Zero-based position of this entry in the log |
tree_size |
Total entries after this append |
head_cid |
Pre-computed CID of the current head CAR |
checkpoint |
Base64-encoded signed checkpoint note |
The receipt is returned synchronously after the entry is sequenced and the CAR is written locally. The Storacha upload happens in the background.
Reads entries from a log.
Caveats: offset (default 0), limit (default 100)
Returns: { entries: [...], total }
Revokes a UCAN delegation. The delegation to revoke must first be stored in the space.
Caveats: cid (CID of stored delegation), delegation (storage delegation)
Workflow:
- Client stores the delegation blob in their space
- Client sends revocation request with the CID
- Service fetches, validates authority, and adds to the revocation log
Only the delegation issuer or upstream authorities can revoke.
These endpoints are unauthenticated and read-only.
Returns current log state.
{ "tree_size": 42, "head_cid": "bafybeig..." }Compatible with the tlog-tiles spec. Proxies tile data from IPFS.
| Endpoint | Description |
|---|---|
GET /logs/{logID}/checkpoint |
Latest signed checkpoint (text/plain) |
GET /logs/{logID}/tile/{level}/{path...} |
Merkle tree tile (application/octet-stream) |
GET /logs/{logID}/tile/entries/{path...} |
Entry bundle (application/octet-stream) |
| Variable | Description | Default |
|---|---|---|
DATA_PATH |
Directory for log storage | ./data |
IPFS_GATEWAY_URL |
IPFS gateway for tile proxying | https://w3s.link |
LOG_LEVEL |
debug / info / warn / error |
info |
PORT |
HTTP server port | 8080 |
UCANLOG_PRIVATE_KEY |
Base64 Ed25519 private key | Generated |
STORACHA_REPLICA_COUNT |
Blob replicas (0 = skip replication) | 2 |
The customer's Storacha space DID is the log identity. Every delegation must target a space DID and include:
space/blob/add— upload blob dataspace/blob/replicate— replicate blobs across storage nodes (setSTORACHA_REPLICA_COUNT=0in dev to skip)space/index/add— register IPNI index CARsupload/add— register uploads in the space
See UCAN_DELEGATION_SPEC for full details.
- Stateless authentication — every request validated independently via UCAN delegation chain
- Delegation theft prevention — invocation must be signed by the same principal who created the delegation
- Revocation authority — issuers and upstream authorities can revoke; recipients cannot
- Pluggable validation — implement
server.RequestValidatorfor additional checks
# Test
go test ./...
# Build
go build -o bin/ucanlog ./cmd/ucanlog- Use a fixed
UCANLOG_PRIVATE_KEYfor a consistent service DID across restarts - Run behind a reverse proxy with TLS
- Back up the SQLite data directory regularly
- Set
STORACHA_REPLICA_COUNT=0for dev/test accounts that don't support replication
- Tessera — cryptographically verifiable transparent logs
- UCAN — User Controlled Authorization Network
- Storacha — decentralized storage with UCAN access control
Apache 2.0 — see LICENSE