Index <= Page index / Phase => Phase 5 – Signatures & crypto
ed25519 with PyNaCl. MVP: canonical JSON (JCS) + signature on laptop, server-side verification. COSE/CBOR kept as a future option if we need compact/IoT envelopes.
Logical payload, format-agnostic:
type: short string (e.g., tx, vote, admin_cmd, msg_forum).version: integer (e.g., 1).issuer: signer id (e.g., mayor:damara, commune:damara, node:K-001).ts: Unix timestamp (seconds) or ISO8601 (pick one; recommended: Unix int).nonce: base64/hex string, 96 random bits (anti-replay).body: business object (vote/forum/admin etc.).Example:
{
"type": "vote",
"version": 1,
"issuer": "mayor:damara",
"ts": 1733900000,
"nonce": "B5ZqkZsLQ3H0R3qqXlQ2LQ==",
"body": {
"poll_id": "budget-2026",
"choice": "yes"
}
}
: between key/value, , between elements, no spaces.true, false, null lowercase.body.Canonical string example (single line):
{"body":{"choice":"yes","poll_id":"budget-2026"},"issuer":"mayor:damara","nonce":"B5ZqkZsLQ3H0R3qqXlQ2LQ==","ts":1733900000,"type":"vote","version":1}
Transported object:
{
"payload": "JCS_CANONICAL_JSON_STRING",
"sig": "BASE64_ED25519",
"kid": "KEY_ID"
}
Example:
{
"payload": "{\"body\":{\"choice\":\"yes\",\"poll_id\":\"budget-2026\"},\"issuer\":\"mayor:damara\",\"nonce\":\"B5ZqkZsLQ3H0R3qqXlQ2LQ==\",\"ts\":1733900000,\"type\":\"vote\",\"version\":1}",
"sig": "qLh7Y8RHdzxYD5t9Cm8yBtV6VvTt4B...base64...",
"kid": "DMR1"
}
payload is a canonical JSON string. Signature = Ed25519 on payload.encode("utf-8").
canonicalize_payload(payload: dict) -> str : JCS string (sorted keys, no spaces, minimal numbers).sign_payload(payload: dict, key_path: str, kid: str) -> dict : canonicalize, sign (Ed25519), return {"payload": payload_str, "sig": base64_sig, "kid": kid}.verify_signed_object(signed_obj: dict, key_index_path: str) -> dict : load pubkey from index by kid, verify signature, parse payload, return dict or raise SignatureError/ValueError.ts window and nonce cache per kid after verification.obbHFL_sign.py / obbHFL_verify.py (sign/verify JSON JCS + Ed25519).obbHFL_forum_emit.py (build+sign msg_forum → outbox JSONL) ; obbHFL_forum_receive.py (verify + anti-replay → inbox_valid/errors)..signed.json, verify with key-index; rerun with same nonce to trigger replay detection.