Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions docs/FOG_ENVELOPE_CANONICALIZATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Fog Envelope Canonicalization and Signing Profile (v0)

This document defines the **recommended evidence profile** for FogVault and FogCompute envelopes until the rules are promoted into first-class schema constraints and ADRs.

## Goals

- deterministic hashing across heterogeneous nodes
- small, auditable signing surface
- stable content references independent of transport
- explicit separation between content hashing, envelope hashing, and settlement logic

## Canonicalization profile

### 1. Canonical JSON

For any JSON payload that is hashed or signed, implementations should:

1. serialize with **JCS** (JSON Canonicalization Scheme; RFC 8785)
2. encode as UTF-8 bytes
3. hash with **SHA-256**

This yields the canonical `payloadHash`.

### 2. Content hashing

Raw content referenced by `ContentRef` should be hashed over the raw bytes, not over JSON wrappers. The digest form should be:

```text
sha256:<lowercase-hex>
```

### 3. Signature algorithm

The default signature algorithm for Fog envelopes and receipts should be:

- **Ed25519** for detached signatures

Recommended signature field encoding:

```text
ed25519:<base64url-signature>
```

### 4. Domain separation

To avoid cross-object signature confusion, signers should sign a domain-separated preimage:

```text
SRCOS-FOG-V1\n
<object-type>\n
<object-id>\n
<payload-hash>
```

Where:
- `<object-type>` is `TopicEnvelope` or `UsageReceipt`
- `<object-id>` is the object URN
- `<payload-hash>` is the canonical SHA-256 digest string

### 5. Encryption metadata

When envelopes are encrypted, the authenticated additional data (AAD) should bind at least:

- `topicId`
- `entryId` or `receiptId`
- `keyEpoch`
- `payloadType`

Recommended default content cipher for topic payloads:

- **XChaCha20-Poly1305**

## Verification order

### TopicEnvelope

1. resolve and verify `ContentRef` digests if present
2. canonicalize `payload`
3. compute `payloadHash`
4. verify detached signature
5. only then evaluate topic semantics / policy

### UsageReceipt

1. canonicalize receipt body
2. compute `receiptHash`
3. verify detached signature
4. verify referenced `WorkOrder` / output refs / settlement mapping

## What this does not settle yet

This v0 profile does **not** yet fix:

- key distribution / rotation mechanics
- threshold or multisignature receipts
- CBOR/COSE variants
- transport-layer framing
- receipt notarization / timestamp authority integration

Those should land in follow-up ADRs and schema revisions.
29 changes: 29 additions & 0 deletions docs/FOG_LAYER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Fog Layer (FogVault + FogCompute)

This document defines the **Fog Layer** contract surface for the SourceOS/SociOS ecosystem.

The fog layer is designed for **heterogeneous, churny, citizen-fog environments** where machines appear and disappear and cannot be treated as durable infrastructure.

## Architecture summary

### FogVault (storage + topic substrate)

- **Local substrate:** nodes expose fast, capacity-managed *local* storage (e.g., LVM-backed PVs via a local CSI driver such as TopoLVM).
- **Distributed meaning + replication:** durability and convergence are provided *above* local storage via **append-only Merkle-log topics** (Hypercore). "Folders" and indexes are derived views.
- **Topic contract:** a topic is an append-only channel with explicit replication policy, membership, and key epochs.

### FogCompute (compute substrate)

- Nodes advertise resource offers (CPU/GPU/RAM/IO windows).
- Requestors submit work orders (image digests + inputs/outputs + verification policy).
- Workers emit usage receipts (metered via OS primitives) and optional settlement events.
- Settlement (tokenization / escrow) is a **pluggable layer**; receipts are the core evidence artifact.

## Contract status

The Fog Layer is represented by the schema set in `schemas/`:

- `Topic.json`, `TopicEnvelope.json`, `ReplicationPolicy.json`, `ContentRef.json`
- `Offer.json`, `WorkOrder.json`, `UsageReceipt.json`, `SettlementEvent.json`

These are **v0 scaffolds** intended to be evolved via ADRs and semver discipline.
9 changes: 9 additions & 0 deletions examples/content_ref.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"digest": "sha256:3d62e3b4c5dd6d04e3d1a2c765a809f0f76ad6f870d13dbb4d4ef7f77e4d2d10",
"sizeBytes": 1048576,
"mediaType": "application/vnd.srcos.fog.block+json",
"uris": [
"file:///srv/fog/topics/fog-cache-health/blocks/3d/62/e3b4",
"hyper://fog-cache-health/blocks/sha256-3d62e3b4c5dd6d04e3d1a2c765a809f0f76ad6f870d13dbb4d4ef7f77e4d2d10"
]
}
34 changes: 34 additions & 0 deletions examples/offer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"id": "urn:srcos:offer:node-17-cpu-gpu-window-a",
"type": "Offer",
"specVersion": "2.0.0",
"provider": {
"subjectId": "urn:srcos:subject:fog-worker-node-17",
"nodeId": "node-17"
},
"resources": {
"cpuCores": 8,
"memoryBytes": 34359738368,
"gpu": {
"count": 1,
"model": "RTX-4090"
},
"storageBytes": 536870912000,
"networkMbps": 1000
},
"availability": {
"timeWindow": "2026-04-16T00:00:00Z/2026-04-16T08:00:00Z",
"maxJobSeconds": 21600
},
"pricing": {
"unit": "fog-credits",
"cpuSecond": 0.002,
"gpuSecond": 0.02,
"gbHour": 0.005
},
"policy": {
"allowWorkloadClasses": ["embedding", "indexing", "batch-inference"],
"privacyMode": "topic-encrypted-only",
"powerCapWatts": 350
}
}
14 changes: 14 additions & 0 deletions examples/replication_policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"replicas": 3,
"minAcks": 1,
"neighborhoods": ["lan", "household", "region"],
"retention": {
"hotDays": 14,
"coldDays": 90,
"maxBytes": 53687091200
},
"compaction": {
"mode": "snapshot",
"intervalEntries": 50000
}
}
12 changes: 12 additions & 0 deletions examples/settlement_event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"id": "urn:srcos:settlement:index-qdrant-shard-20260416-01",
"type": "SettlementEvent",
"specVersion": "2.0.0",
"receiptId": "urn:srcos:receipt:usage:index-qdrant-shard-20260416-01",
"amount": {
"unit": "fog-credits",
"value": 12.84
},
"backend": "internal-ledger",
"txRef": "ledger://fog-credits/2026/04/16/txn-000001"
}
31 changes: 31 additions & 0 deletions examples/topic.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"id": "urn:srcos:topic:fog-cache-health",
"type": "Topic",
"specVersion": "2.0.0",
"name": "fog.cache.health",
"description": "Health/cache topic for edge-local fog state with append-only Merkle-log replication.",
"replication": {
"replicas": 3,
"minAcks": 1,
"neighborhoods": ["lan", "region"],
"retention": {
"hotDays": 7,
"coldDays": 30,
"maxBytes": 10737418240
},
"compaction": {
"mode": "checkpoint",
"intervalEntries": 10000
}
},
"encryption": {
"cipherSuite": "xchacha20poly1305",
"keyEpoch": 4,
"keyRef": "urn:srcos:key:topic:fog-cache-health:epoch:4"
},
"members": [
"urn:srcos:community:fog-workers",
"urn:srcos:community:fog-observers"
],
"labels": ["fog", "cache", "ephemeral"]
}
33 changes: 33 additions & 0 deletions examples/topic_envelope.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"entryId": "urn:srcos:topic-entry:fog-cache-health:000001",
"topicId": "urn:srcos:topic:fog-cache-health",
"specVersion": "2.0.0",
"occurredAt": "2026-04-16T02:15:00Z",
"author": {
"subjectId": "urn:srcos:subject:fog-worker-node-17",
"nodeId": "node-17"
},
"payloadType": "PutBlob",
"payload": {
"path": "/cache/health/worker-17.json",
"contentRef": {
"digest": "sha256:3d62e3b4c5dd6d04e3d1a2c765a809f0f76ad6f870d13dbb4d4ef7f77e4d2d10",
"sizeBytes": 1048576,
"mediaType": "application/json"
}
},
"integrity": {
"content": {
"digest": "sha256:3d62e3b4c5dd6d04e3d1a2c765a809f0f76ad6f870d13dbb4d4ef7f77e4d2d10",
"sizeBytes": 1048576,
"mediaType": "application/json"
},
"payloadHash": "sha256:9cd8d6d35b07be7db0d8904b5bd808c95bd1ef674353abce6ebf58c480644e12",
"signature": "ed25519:example-signature-topic-entry"
},
"encryption": {
"cipherSuite": "xchacha20poly1305",
"keyEpoch": 4,
"aad": "topic=fog.cache.health"
}
}
34 changes: 34 additions & 0 deletions examples/usage_receipt.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"id": "urn:srcos:receipt:usage:index-qdrant-shard-20260416-01",
"type": "UsageReceipt",
"specVersion": "2.0.0",
"workOrderId": "urn:srcos:workorder:index-qdrant-shard-20260416-01",
"provider": {
"subjectId": "urn:srcos:subject:fog-worker-node-17",
"nodeId": "node-17"
},
"startedAt": "2026-04-16T02:20:00Z",
"endedAt": "2026-04-16T02:28:42Z",
"exit": {
"code": 0,
"status": "completed"
},
"usage": {
"cpuSeconds": 3812.41,
"memoryPeakBytes": 8912896000,
"ioReadBytes": 721420288,
"ioWriteBytes": 361758720,
"gpuSeconds": 0
},
"outputs": [
{
"digest": "sha256:2222222222222222222222222222222222222222222222222222222222222222",
"mediaType": "application/vnd.qdrant.snapshot",
"sizeBytes": 285212672
}
],
"integrity": {
"receiptHash": "sha256:3333333333333333333333333333333333333333333333333333333333333333",
"signature": "ed25519:example-signature-usage-receipt"
}
}
37 changes: 37 additions & 0 deletions examples/workorder.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"id": "urn:srcos:workorder:index-qdrant-shard-20260416-01",
"type": "WorkOrder",
"specVersion": "2.0.0",
"requestor": {
"subjectId": "urn:srcos:subject:mesh-broker-1"
},
"workload": {
"image": "ghcr.io/socioprophet/fog-indexer@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"command": ["/app/index", "--topic", "fog.cache.health", "--shard", "17"],
"env": {
"QDRANT_URL": "http://qdrant.service.local:6333",
"TOPIC_ID": "urn:srcos:topic:fog-cache-health"
}
},
"inputs": [
{
"digest": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
"sizeBytes": 52428800,
"mediaType": "application/x-ndjson"
}
],
"outputs": [
{
"digest": "sha256:2222222222222222222222222222222222222222222222222222222222222222",
"mediaType": "application/vnd.qdrant.snapshot"
}
],
"verification": {
"mode": "replicate",
"replicas": 2
},
"placement": {
"requireGpu": false,
"neighborhood": "lan"
}
}
34 changes: 34 additions & 0 deletions schemas/ContentRef.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://schemas.srcos.ai/v2/ContentRef.json",
"title": "ContentRef",
"description": "A content-addressed reference to bytes (blob/chunk/manifest) used by Fog topics and work orders.",
"type": "object",
"additionalProperties": false,
"required": ["digest"],
"properties": {
"digest": {
"type": "string",
"description": "Digest string (recommended form: <algo>:<hex> e.g. sha256:...)."
},
"sizeBytes": {
"type": "integer",
"minimum": 0,
"description": "Optional size hint in bytes."
},
"mediaType": {
"type": ["string", "null"],
"description": "Optional IANA media type hint."
},
"uris": {
"type": "array",
"items": {"type": "string"},
"description": "Optional locator hints (e.g. file://, s3://, ipfs://, hyper://, https://)."
},
"chunks": {
"type": "array",
"items": {"$ref": "ContentRef.json"},
"description": "Optional chunk list when the content is a manifest-of-chunks."
}
}
}
Loading
Loading