Trusty: provenance library workspace (initial import)
This commit is contained in:
92
docs/twin-coupling.md
Normal file
92
docs/twin-coupling.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Twin Coupling -- Data Convention
|
||||
|
||||
## Problem
|
||||
|
||||
A digital-twin computation ingests readings from one or more sensor
|
||||
chains and produces a derived result. The result is appended to its own
|
||||
trusty chain (separate `entity_id`). How does an external verifier
|
||||
confirm which sensor rows fed the computation?
|
||||
|
||||
## Convention
|
||||
|
||||
The twin row carries a `source_refs` array inside its `data` field:
|
||||
|
||||
```json
|
||||
{
|
||||
"computation": "rolling_avg_temp_c",
|
||||
"result": 21.37,
|
||||
"source_refs": [
|
||||
{"chain_id": "chain_sensor-001_...", "sequence": 0, "row_hash": "ae1cfe445cda1f6d"},
|
||||
{"chain_id": "chain_sensor-001_...", "sequence": 1, "row_hash": "dee9856d170787cf"},
|
||||
{"chain_id": "chain_sensor-001_...", "sequence": 2, "row_hash": "26cd125f051243cf"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Each entry is:
|
||||
|
||||
| Field | Source | Purpose |
|
||||
|------------|---------------------------------|--------------------------------------------|
|
||||
| `chain_id` | `AppendResult.chain_id` | Identifies which sensor chain |
|
||||
| `sequence` | `AppendResult.sequence` | Row position within that chain |
|
||||
| `row_hash` | `AppendResult.row_hash` | Tamper-evident fingerprint of the row |
|
||||
|
||||
Because `data` is already part of the payload that `row_hash` commits
|
||||
to, the `source_refs` array is itself hash-protected. Altering any
|
||||
reference after the fact invalidates the twin row's `row_hash` and
|
||||
fails `verify_chain`.
|
||||
|
||||
## Verification flow (two ProofBundles)
|
||||
|
||||
An external verifier needs no database access -- only two
|
||||
`ProofBundle` blobs exported via `Trusty::export_bundle`:
|
||||
|
||||
1. `sensor_bundle.verify(&sip_key)` -- confirms the sensor chain is
|
||||
internally consistent.
|
||||
2. `twin_bundle.verify(&sip_key)` -- confirms the twin chain is
|
||||
internally consistent.
|
||||
3. Walk twin rows; for each `source_refs` entry, look up the matching
|
||||
row in `sensor_bundle.rows` by `chain_id` + `sequence` and assert
|
||||
`row_hash` matches.
|
||||
|
||||
If all three checks pass, the verifier knows:
|
||||
- The sensor readings are unaltered.
|
||||
- The twin computation row is unaltered.
|
||||
- The twin row commits to exactly those sensor row_hashes at write time.
|
||||
|
||||
See `crates/trusty-sqlite/examples/twin_coupling.rs` for a runnable
|
||||
end-to-end demo.
|
||||
|
||||
## Design decisions
|
||||
|
||||
**Why `data` field, not a new `break_reason` variant.**
|
||||
`break_reason` marks loss-of-continuity (tamper, gap, domain mismatch).
|
||||
A twin derivation is a planned event, not an anomaly. Mixing the two
|
||||
pollutes `breaks_since()` as an alerting surface and requires callers
|
||||
to filter by break kind.
|
||||
|
||||
**Why not a separate `twin_reference` table.**
|
||||
A join table outside the hash surface cannot be verified from a
|
||||
ProofBundle alone. The verifier would need database access, breaking
|
||||
the self-contained export contract. `source_refs` in `data` is
|
||||
verifiable anywhere the bundle travels.
|
||||
|
||||
**What this does NOT prove.**
|
||||
The convention proves the twin row committed to those row_hashes at
|
||||
write time. It does not prove the computation is correct (the twin
|
||||
operator could have computed a wrong average and still referenced the
|
||||
right sensor rows). Computation correctness is out of scope for trusty;
|
||||
it belongs to a separate audit or reproducibility layer.
|
||||
|
||||
## Multi-sensor / multi-chain refs
|
||||
|
||||
`source_refs` can mix `chain_id` values from different sensor entities.
|
||||
The verifier simply exports a ProofBundle per sensor entity and checks
|
||||
each ref against the appropriate bundle.
|
||||
|
||||
```json
|
||||
"source_refs": [
|
||||
{"chain_id": "chain_sensor-001_...", "sequence": 5, "row_hash": "..."},
|
||||
{"chain_id": "chain_sensor-002_...", "sequence": 3, "row_hash": "..."}
|
||||
]
|
||||
```
|
||||
Reference in New Issue
Block a user