csoai-scitt-ts
Minimal SCITT Transparency Service for CSOAI measurement cards.
Registers CSOAI measurement cards as SCITT Signed Statements (RFC 9943) backed by an append-only RFC 9162 Merkle transparency log. Issues COSE Receipts (RFC 9052) with inclusion proofs that are verifiable offline.
Architecture
┌─────────────────┐ JSON card ┌──────────────────────┐
│ CSOAI Council │ ─────────────────>│ card_to_signed_ │
│ (BFT signer) │ │ statement() │
└─────────────────┘ │ COSE_Sign1 (EdDSA) │
└──────────┬───────────┘
│ CBOR tag-18
v
┌──────────────────────┐
│ TransparencyService │
│ ┌────────────────┐ │
│ │ SQLite (append- │ │
│ │ only Merkle log)│ │
│ └────────────────┘ │
│ │
│ register() → receipt│
└──────────┬───────────┘
│
┌─────────────┼─────────────┐
v v
COSE Receipt Transparent
(inclusion proof) Statement
│ (stmt + receipt)
v
┌──────────────────┐
│ verify_csoai_ │
│ receipt() │
│ (offline, no TS │
│ needed) │
└──────────────────┘
Standards
| Standard | Role |
|---|---|
| RFC 9943 | SCITT Architecture — Signed Statements, Transparent Statements, Receipts |
| RFC 9052/9053 | COSE_Sign1 — the wire format for statements and receipts |
| RFC 9162 | Certificate Transparency v2 — SHA-256 Merkle tree, inclusion/consistency proofs |
| RFC 8392 | CWT Claims — issuer (iss) and subject (sub) in the COSE protected header |
| RFC 9597 | CWT Claims in COSE Headers (label 15) |
Key Design Decisions
- Python (not Go) — matches CSOAI's existing stack (SOV3, measurement engine).
- Ed25519 (COSE algorithm ID
-8,"EdDSA") — matches CSOAI's existing Ed25519 key infrastructure. - SQLite for Merkle log storage — simple, portable, no external database required. WAL mode for concurrency.
scitt-cosesubstrate — builds on the tested, cross-validatedscitt-coselibrary for COSE_Sign1, Merkle primitives, and receipt generation/verification. This library implements RFC 9052 from scratch (no external COSE lib dependency) and is cross-verified against Go and pycose implementations.- CWT Claims at label 15 (not 13) — per RFC 9597 §2. Label 13 is
kcwt(RFC 9528), a different parameter that is sometimes mistakenly used. - Offline verification — receipts are self-contained COSE_Sign1 objects; verify with only the receipt bytes, the leaf entry, and the log's public key. No network required.
- Append-only — entries are never deleted or reordered. New registrations extend the tree and change the Merkle root.
Installation
pip install -e .
# or
pip install cbor2 cryptography scitt-cose
Quick Start
from cryptography.hazmat.primitives.asymmetric import ed25519
from cryptography.hazmat.primitives import serialization
from csoai_scitt_ts.statement import card_to_signed_statement
from csoai_scitt_ts.service import TransparencyService
from csoai_scitt_ts.verify import verify_csoai_receipt
# Generate keys
issuer_sk = ed25519.Ed25519PrivateKey.generate()
issuer_pem = issuer_sk.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.PKCS8,
serialization.NoEncryption(),
)
log_sk = ed25519.Ed25519PrivateKey.generate()
log_pem = log_sk.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.PKCS8,
serialization.NoEncryption(),
)
log_pub = log_sk.public_key().public_bytes(
serialization.Encoding.PEM,
serialization.PublicFormat.SubjectPublicKeyInfo,
)
# Create a measurement card
card = {
"card_id": "CARD-2026-001",
"subject": "https://meok.ai/product/quantum-shield",
"axes": [
{"name": "robustness", "score": 0.87},
{"name": "explainability", "score": 0.74},
],
"overall_score": 0.84,
}
# Sign as a SCITT Signed Statement
stmt = card_to_signed_statement(card, private_key_pem=issuer_pem)
# Register with the Transparency Service
ts = TransparencyService(":memory:", log_pem)
result = ts.register(stmt)
print(f"Entry {result.entry_id}, tree size {result.tree_size}")
print(f"Merkle root: {result.merkle_root_hex}")
# Verify the receipt (offline)
vr = verify_csoai_receipt(
result.receipt,
leaf_entry_hex=stmt.hex(),
log_public_key_pem=log_pub,
)
assert vr.receipt_ok
print(f"Receipt verified! Root: {vr.merkle_root}")
HTTP API
# Start the server
csoai-scitt-ts serve --port 8443 --db ./scitt.db --key ./log-key.pem
Endpoints
| Method | Path | Description |
|---|---|---|
POST |
/register |
Register a measurement card (JSON body) |
GET |
/entries/{id} |
Get entry metadata by id |
GET |
/receipt/{id} |
Get the COSE Receipt for an entry |
GET |
/tree |
Current tree size and Merkle root |
GET |
/health |
Health check |
Register a card
curl -X POST http://localhost:8443/register \
-H "Content-Type: application/json" \
-d '{"card_id":"CARD-001","score":0.95}'
Response:
{
"entry_id": 1,
"leaf_hash": "...",
"tree_size": 1,
"merkle_root": "...",
"receipt_b64": "...",
"statement_b64": "..."
}
Get a receipt
curl http://localhost:8443/receipt/1 --output receipt.cbor
The receipt is COSE-encoded CBOR (Content-Type: application/cbor).
Package Structure
csoai-scitt-ts/
├── pyproject.toml # Package metadata
├── README.md
├── csoai_scitt_ts/
│ ├── __init__.py # Package init
│ ├── statement.py # Card → COSE_Sign1 Signed Statement
│ ├── service.py # Transparency Service (SQLite Merkle log)
│ ├── receipt.py # Receipt generation & transparent statements
│ ├── verify.py # Receipt verification (offline)
│ ├── api.py # HTTP API
│ └── cli.py # CLI entry point
└── tests/
└── test_service.py # Comprehensive test suite
Testing
pip install -e ".[dev]"
pytest -v
Compatibility Notes
- COSE algorithm -8 (EdDSA): The SCITT spec uses -8 for EdDSA, which maps to Ed25519. This matches CSOAI's existing key infrastructure. The
scitt-coselibrary handles the COSE_Sign1 construction from scratch overcbor2+cryptography. - CWT Claims at label 15: Per RFC 9597, not label 13 (
kcwt). This is important for interoperability — some libraries incorrectly use label 13. - Merkle tree: RFC 9162 SHA-256 construction (same as CT v2). Domain-separated leaf hashes (
0x00prefix) and interior node hashes (0x01prefix). - Receipt format: Tracks
draft-ietf-cose-merkle-tree-proofs-18— vds=1 (RFC9162_SHA256) at label 395, inclusion proofs at label 396.
License
MIT
Metadata
Release files for csoai-scitt-ts 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| csoai_scitt_ts-0.1.0.tar.gz | 19.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| csoai_scitt_ts-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 35.6 kB
Release files / csoai_scitt_ts-0.1.0.tar.gz
| Download URL | csoai_scitt_ts-0.1.0.tar.gz |
|---|---|
| Size | 19.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
98d49a8924680927b16f567de192a86fe04247e814d40c90722b9d6535c8f1cd
|
|
BLAKE2b-256 checksum How to use checksums |
9e4b23b72ba315723e447ac1734649656c6b5770132873b1cab540a770b72214
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.12
|
Release files / csoai_scitt_ts-0.1.0-py3-none-any.whl
| Download URL | csoai_scitt_ts-0.1.0-py3-none-any.whl |
|---|---|
| Size | 16.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e06768c3e9b75e773b39e806ce21f30c2cb2eed0a71cedae50f1f296658ada51
|
|
BLAKE2b-256 checksum How to use checksums |
a7ebced14249645e4b09f19f54cf126699a399441d1f1bc73439f5376e91b977
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.12
|