Reference View as Markdown

Signatures

Every answer is signed, so you, or whoever you answer to, can prove later exactly what we said, about which address, at which block. Checking it is optional.

What is signed

  • AlgorithmEd25519. The signature is base64url, in signature.sig.
  • InputThe answer as JSON, with its signature field removed, in canonical form (RFC 8785, JSON Canonicalization Scheme: keys sorted, no spaces).
  • Which keysignature.key_id names the key. The public keys are at GET /v1/keys, as a JWKS (kty OKP, crv Ed25519). Fetch them once and keep them.
  • What it coversEverything in the answer: the verdict, the reasons, the block and as_of it was true at, and its request_id, so an answer can't be passed off as another request's.

Checking one

In JavaScript, with the browser's or Node's own crypto and the canonicalize package (RFC 8785):

import canonicalize from "canonicalize"; const { keys } = await (await fetch("https://api.lorglabs.com/v1/keys")).json(); async function isOurs(answer) { const { signature, ...signed } = answer; const jwk = keys.find((k) => k.kid === signature.key_id); if (!jwk) return false; const key = await crypto.subtle.importKey("jwk", { kty: "OKP", crv: "Ed25519", x: jwk.x }, { name: "Ed25519" }, false, ["verify"]); const sig = Uint8Array.from(atob(signature.sig.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0)); return crypto.subtle.verify({ name: "Ed25519" }, key, sig, new TextEncoder().encode(canonicalize(signed))); }

Each service signs with its own key: api.lorglabs.com's answers verify against its /v1/keys, the sandbox's against its own.

When it matters

For a platform, a signed answer is a record: if a user asks why a trade was refused, or allowed, the answer you got is the proof, with the block it was true at. For an agent acting for someone, it shows the owner what the agent was told before it moved their money.