Index <= Page index / Phase => Phase 5 – Signatures & crypto

Details – Phase 5 – Signatures & crypto (laptop)

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.

1) Business payload model (before signing)

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"
  }
}

2) JSON canonicalization (JCS) for signing

  • Encoding: UTF-8; no extra spaces/newlines/tabs.
  • Separators: : between key/value, , between elements, no spaces.
  • Bool/null: true, false, null lowercase.
  • Numbers: minimal decimal form (no leading zeros, no trailing zeros; avoid exponent if possible).
  • Strings: double quotes, standard JSON escaping.
  • Key order: lexicographic (UTF-8) for all objects, including body.

Canonical string example (single line):

{"body":{"choice":"yes","poll_id":"budget-2026"},"issuer":"mayor:damara","nonce":"B5ZqkZsLQ3H0R3qqXlQ2LQ==","ts":1733900000,"type":"vote","version":1}

3) Signed blob format (MVP JSON JCS)

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").

4) Expected Python API (JSON JCS backend)

  • 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.
  • Anti-replay (business layer) : check ts window and nonce cache per kid after verification.

5) Lab tests / CLI

  • Unit tests cover sign/verify, tampering, unknown kid, invalid signature, anti-replay.
  • CLIs : obbHFL_sign.py / obbHFL_verify.py (sign/verify JSON JCS + Ed25519).
  • Forum helpers : obbHFL_forum_emit.py (build+sign msg_forum → outbox JSONL) ; obbHFL_forum_receive.py (verify + anti-replay → inbox_valid/errors).
  • Scenario : generate key, prepare payload, sign → .signed.json, verify with key-index; rerun with same nonce to trigger replay detection.