Skip to content

bakeoff: result signing and verification scheme #16

@AlbinoGeek

Description

@AlbinoGeek

Bastion (J-5) — bakeoff: result signing and verification scheme — 221424ZMAY26

Spun off from #13 (221322ZMAY26 reply). Deferred pending scheme definition.


Background

Standalone runner writes results to results/<model>/<timestamp>.json. #13 established results should be signed and verified — scheme TBD. This thread is the home for that design.


Q1 — Signing scheme

  • Ed25519 — fast, small signatures (64 bytes), widely supported. Asymmetric: runner holds private key, verifier holds public key only.
  • HMAC-SHA256 — symmetric; simpler to implement, no asymmetric key infrastructure. Requires distributing a shared secret to every authorized runner.
  • GPG / minisign — well-known tooling; heavier dependency.

Recommendation: Ed25519. Asymmetric signing means the verifier (submission pipeline or bakeoff-results query layer) never holds the signing key — compromising the verifier does not compromise result integrity. Minisign is a clean minimal implementation if a standalone tool is preferred over bare crypto primitives.


Q2 — Key distribution

  • Per-runner keys: each runner generates its own keypair; public key registered in runners.public_key. Supports attribution per runner; revocation = mark runner DEAD, remove public key from trusted set.
  • Shared org key: one keypair for all authorized runners. Simpler; no per-runner attribution.

Recommendation: per-runner keys. Aligns with the runners table already tracking runner identity. runners.public_key TEXT stores the Ed25519 public key. Revocation is clean and already in the dead-runner detection path.


Q3 — What is signed?

  • Option A: raw result file bytes — sign(file_bytes).
  • Option B: canonical JSON (sorted keys, no whitespace) — sign(canonical(result)).
  • Option C: content hash sidecar — sign(SHA256(file_bytes)); embed signature + hash in results/<model>/<timestamp>.json.sig.

Recommendation: Option C. Sidecar keeps result file unchanged and human-readable. Verification is a two-step hash check then signature verify. Sidecar format:

{
  "sha256": "<hex>",
  "signature": "<base64>",
  "runner_id": "<runner_id>",
  "signed_at": "<timestamptz>"
}

Q4 — Verification trigger

When is the signature checked?

  • At submission time (before DB insert into run_model_metrics)
  • At display time (bakeoff-results query layer)
  • Both

Recommendation: submission time as the gate. Reject unsigned or invalid-signature results before they enter the DB. Display-time re-verification is optional hardening — add only if the submission pipeline is not trusted as a sufficient choke point.


@gissf1 — opinions on Q1–Q4 above?

— Bastion

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions