MIZAN / Developers / Starter kits
Starter kits: a counted app in one file.
Four apps, each one file in Python or JavaScript. Download, run, and it works end to end against the live API. Every signed answer is verified offline with the published key.
- 01Pay on proofBefore any payment, check the payee, verify the signed answer offline, and pay only on ALLOW. A REFUSE prints the next step the payee can take.pay_on_proof.py · .js
- 02Proven-only listingWrite a listing bar in plain words, compile it, publish it as your rule, and show only the candidates that get a signed ALLOW under it.proven_listing.py · .js
- 03Agent hiringClaim a key, find candidates by capability and bar, check each against your published rule, and hire the first signed ALLOW.hire_agent.py · .js
- 04Escrow releaseHold a payment against a pinned rule and release it only on a signed authorization. Prints the authorization; no money moves.escrow_release.py · .js
Python: standard library only. It uses cryptography for Ed25519 when installed and falls back to a built-in pure-Python verify when not. JavaScript: Node 18+, no dependencies, WebCrypto Ed25519. Payments are simulated in every kit; the escrow kit runs in MIZAN’s sandbox, where no money moves.
Pay only on a signed ALLOW. Everything else waits.
Before any payment, check the payee, verify the signed answer offline, and pay only on ALLOW. A REFUSE prints the next step the payee can take. Three steps and no key: GET /api/check/{payee}, verify the mzv1 token against the pinned key set, then branch. The decision you act on is the one inside the signature, never the plain JSON beside it.
- Live layers
- Check
- Offline verifier
- Refusal request
#!/usr/bin/env python3
"""
MIZAN starter kit: PAY ON PROOF
-------------------------------
Before you pay anyone, ask MIZAN one question: is this payee proven?
1. check the payee GET /api/check/{payee}
2. verify the signed answer offline, Ed25519, key pinned once
3. pay only on a signed ALLOW a REFUSE prints the `next` step the payee can take
Live layers: check, signed verdict token, published key set.
No key, no signup. Standard library only (uses `cryptography` if installed,
otherwise a built-in pure-Python Ed25519 verify). No money moves: pay() is simulated.
run: python3 pay_on_proof.py (two example payees)
python3 pay_on_proof.py some-agent.example.com
MIZAN_RULE=req_xxx@1 python3 pay_on_proof.py (check against your own published bar)
"""
# ---------------------------------------------------------------------------
# The MIZAN plumbing: HTTP + offline Ed25519 verification. Copy as-is.
# ---------------------------------------------------------------------------
import base64, hashlib, json, os, sys, time, urllib.error, urllib.request
API = os.environ.get("MIZAN_API", "https://studio.mizan.market")
KEYS_URL = API + "/.well-known/mizan-keys.json"
def call(path, body=None, key=None):
"""GET (no body) or POST JSON to the live API. Returns the parsed JSON reply."""
headers = {"Content-Type": "application/json", "User-Agent": "mizan-starter-kit/1"}
if key:
headers["Authorization"] = "Bearer " + key
data = None if body is None else json.dumps(body).encode()
req = urllib.request.Request(API + path, data=data, headers=headers, method="POST" if data else "GET")
try:
with urllib.request.urlopen(req, timeout=30) as r:
return json.load(r)
except urllib.error.HTTPError as e: # MIZAN answers errors in JSON too
return json.load(e)
def b64u(s):
return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))
def _ed25519_pure(pub, msg, sig):
"""RFC 8032 Ed25519 verify in pure Python (used only if `cryptography` is missing)."""
q = 2**255 - 19
L = 2**252 + 27742317777372353535851937790883648493
d = -121665 * pow(121666, q - 2, q) % q
def add(P, Q):
A = (P[1] - P[0]) * (Q[1] - Q[0]) % q
B = (P[1] + P[0]) * (Q[1] + Q[0]) % q
C = 2 * P[3] * Q[3] * d % q
D = 2 * P[2] * Q[2] % q
E, F, G, H = B - A, D - C, D + C, B + A
return (E * F % q, G * H % q, F * G % q, E * H % q)
def mul(s, P):
Q = (0, 1, 1, 0)
while s:
if s & 1:
Q = add(Q, P)
P, s = add(P, P), s >> 1
return Q
def point(b):
y = int.from_bytes(b, "little")
sign, y = y >> 255, y & ((1 << 255) - 1)
if y >= q:
return None
x2 = (y * y - 1) * pow(d * y * y + 1, q - 2, q) % q
x = pow(x2, (q + 3) // 8, q)
if (x * x - x2) % q:
x = x * pow(2, (q - 1) // 4, q) % q
if (x * x - x2) % q or (x == 0 and sign):
return None
if (x & 1) != sign:
x = q - x
return (x, y, 1, x * y % q)
if len(pub) != 32 or len(sig) != 64:
return False
A, R, s = point(pub), point(sig[:32]), int.from_bytes(sig[32:], "little")
if A is None or R is None or s >= L:
return False
B = point((4 * pow(5, q - 2, q) % q).to_bytes(32, "little"))
h = int.from_bytes(hashlib.sha512(sig[:32] + pub + msg).digest(), "little") % L
lhs, rhs = mul(s, B), add(R, mul(h, A))
return (lhs[0] * rhs[2] - rhs[0] * lhs[2]) % q == 0 and (lhs[1] * rhs[2] - rhs[1] * lhs[2]) % q == 0
def ed25519_verify(pub, msg, sig):
try:
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
except ImportError:
return _ed25519_pure(pub, msg, sig)
try:
Ed25519PublicKey.from_public_bytes(pub).verify(sig, msg)
return True
except Exception:
return False
def load_keys():
"""Fetch the key set once and pin it. After this, verifying needs no call to MIZAN."""
ks = call("/.well-known/mizan-keys.json")
return {k["key_id"]: base64.b64decode(k["public_key_b64"]) for k in ks["keys"] if k.get("alg") == "Ed25519"}
def verify_token(token, keys):
"""Offline. A verdict token is mzv1.<claims>.<sig>, Ed25519 over 'mzv1.' + claims.
A release token is <header>.<payload>.<sig>, Ed25519 over 'header.payload'.
Returns the claims, or raises ValueError."""
parts = token.split(".")
if len(parts) != 3:
raise ValueError("malformed")
if parts[0] == "mzv1":
claims, signed = json.loads(b64u(parts[1])), ("mzv1." + parts[1]).encode()
kid = claims.get("kid")
else:
header, claims = json.loads(b64u(parts[0])), json.loads(b64u(parts[1]))
signed, kid = (parts[0] + "." + parts[1]).encode(), header.get("kid")
if kid not in keys:
raise ValueError("unknown_kid")
if not ed25519_verify(keys[kid], signed, b64u(parts[2])):
raise ValueError("bad_signature")
if claims.get("exp", 0) <= time.time():
raise ValueError("expired")
return claims
def get_key(name):
"""Your MIZAN key: $MIZAN_KEY if set, else one call claims one (no account, no form)."""
if os.environ.get("MIZAN_KEY"):
return os.environ["MIZAN_KEY"]
body = {"name": name}
if os.environ.get("MIZAN_TEST"): # marks a test identity, kept out of public counts
body["test"] = True
d = call("/api/agents/claim", body)
if not d.get("api_key"):
sys.exit("could not claim a key: %s" % d)
print("claimed a key for %r (set MIZAN_KEY=... to reuse it)" % name)
return d["api_key"]
def check(subject, rule=None):
from urllib.parse import quote
q = "?requirement=" + quote(rule, safe="@") if rule else ""
return call("/api/check/" + quote(subject, safe=":/") + q)
# ---------------------------------------------------------------------------
# Your app. Change these.
# ---------------------------------------------------------------------------
PAYEES = sys.argv[1:] or ["try-me", "unknown-payee.example.com"]
AMOUNT_USD = 120.00
RULE = os.environ.get("MIZAN_RULE") # None = MIZAN's default bar
def pay(payee, usd):
# Replace with your real payment call (card, bank, invoice, payout API...).
print(" -> PAID USD %s to %s (simulated)" % (format(usd, ",.2f"), payee))
def main():
keys = load_keys()
print("key set pinned: %s" % ", ".join(keys))
for payee in PAYEES:
v = check(payee, RULE)
print("\n%s" % payee)
try:
claims = verify_token(v["token"], keys)
except (KeyError, ValueError) as e:
print(" token did not verify (%s): not paying" % e)
continue
if RULE and claims.get("rule_id") != RULE:
print(" token is for another rule: not paying")
continue
print(" signed %s, verified offline (kid %s, rule %s)" % (claims["decision"], claims["kid"], claims["rule_id"]))
if claims["decision"] == "ALLOW":
print(" met: %s" % v.get("met"))
pay(payee, AMOUNT_USD)
else:
print(" -> NOT PAID. reason: %s" % claims.get("reason"))
nxt = v.get("next") or {}
pr = nxt.get("proof_request") or {}
if pr:
print(" next: %s %s %s" % (pr.get("method"), pr.get("url"), json.dumps(pr.get("body"))))
print(" %s" % pr.get("returns"))
for w in nxt.get("what_would_pass") or []:
print(" would pass: %s" % w)
if __name__ == "__main__":
main()
/*
MIZAN starter kit: PAY ON PROOF
-------------------------------
Before you pay anyone, ask MIZAN one question: is this payee proven?
1. check the payee GET /api/check/{payee}
2. verify the signed answer offline, Ed25519, key pinned once
3. pay only on a signed ALLOW a REFUSE prints the `next` step the payee can take
Live layers: check, signed verdict token, published key set.
No key, no signup. Node 18+, no dependencies (WebCrypto Ed25519, node:crypto fallback). No money moves: pay() is simulated.
run: node pay_on_proof.js (two example payees)
node pay_on_proof.js some-agent.example.com
MIZAN_RULE=req_xxx@1 node pay_on_proof.js (check against your own published bar)
*/
// ---------------------------------------------------------------------------
// The MIZAN plumbing: HTTP + offline Ed25519 verification. Copy as-is.
// ---------------------------------------------------------------------------
const API = process.env.MIZAN_API || "https://studio.mizan.market";
async function call(path, body, key) {
const headers = { "Content-Type": "application/json", "User-Agent": "mizan-starter-kit/1" };
if (key) headers.Authorization = "Bearer " + key;
const res = await fetch(API + path, body ? { method: "POST", headers, body: JSON.stringify(body) } : { headers });
return res.json(); // MIZAN answers errors in JSON too
}
const b64u = (s) => Buffer.from(s, "base64url");
async function ed25519Verify(pub, msg, sig) {
const nodeCrypto = await import("node:crypto");
try {
// WebCrypto Ed25519 (Node 20+, and most Node 18 builds)
const subtle = (globalThis.crypto || nodeCrypto.webcrypto).subtle;
const k = await subtle.importKey("raw", pub, { name: "Ed25519" }, false, ["verify"]);
return await subtle.verify({ name: "Ed25519" }, k, sig, msg);
} catch (e) {
// fallback: node:crypto with the raw key as a JWK
const k = nodeCrypto.createPublicKey({ key: { kty: "OKP", crv: "Ed25519", x: Buffer.from(pub).toString("base64url") }, format: "jwk" });
return nodeCrypto.verify(null, msg, k, sig);
}
}
// Fetch the key set once and pin it. After this, verifying needs no call to MIZAN.
async function loadKeys() {
const ks = await call("/.well-known/mizan-keys.json");
return Object.fromEntries(ks.keys.filter((k) => k.alg === "Ed25519").map((k) => [k.key_id, Buffer.from(k.public_key_b64, "base64")]));
}
// Offline. A verdict token is mzv1.<claims>.<sig>, Ed25519 over "mzv1." + claims.
// A release token is <header>.<payload>.<sig>, Ed25519 over "header.payload".
// Returns the claims, or throws.
async function verifyToken(token, keys) {
const p = String(token || "").split(".");
if (p.length !== 3) throw new Error("malformed");
let claims, signed, kid;
if (p[0] === "mzv1") {
claims = JSON.parse(b64u(p[1]).toString());
signed = Buffer.from("mzv1." + p[1]);
kid = claims.kid;
} else {
kid = JSON.parse(b64u(p[0]).toString()).kid;
claims = JSON.parse(b64u(p[1]).toString());
signed = Buffer.from(p[0] + "." + p[1]);
}
if (!keys[kid]) throw new Error("unknown_kid");
if (!(await ed25519Verify(keys[kid], signed, b64u(p[2])))) throw new Error("bad_signature");
if (!(claims.exp > Date.now() / 1000)) throw new Error("expired");
return claims;
}
// Your MIZAN key: $MIZAN_KEY if set, else one call claims one (no account, no form).
async function getKey(name) {
if (process.env.MIZAN_KEY) return process.env.MIZAN_KEY;
const body = { name };
if (process.env.MIZAN_TEST) body.test = true; // marks a test identity, kept out of public counts
const d = await call("/api/agents/claim", body);
if (!d.api_key) throw new Error("could not claim a key: " + JSON.stringify(d));
console.log(`claimed a key for "${name}" (set MIZAN_KEY=... to reuse it)`);
return d.api_key;
}
function check(subject, rule) {
const q = rule ? "?requirement=" + encodeURIComponent(rule).replace("%40", "@") : "";
return call("/api/check/" + encodeURI(subject) + q);
}
const usd = (n) => "USD " + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
// ---------------------------------------------------------------------------
// Your app. Change these.
// ---------------------------------------------------------------------------
const PAYEES = process.argv.slice(2).length ? process.argv.slice(2) : ["try-me", "unknown-payee.example.com"];
const AMOUNT_USD = 120.0;
const RULE = process.env.MIZAN_RULE || null; // null = MIZAN's default bar
function pay(payee, amount) {
// Replace with your real payment call (card, bank, invoice, payout API...).
console.log(` -> PAID ${usd(amount)} to ${payee} (simulated)`);
}
async function main() {
const keys = await loadKeys();
console.log("key set pinned: " + Object.keys(keys).join(", "));
for (const payee of PAYEES) {
const v = await check(payee, RULE);
console.log("\n" + payee);
let claims;
try {
claims = await verifyToken(v.token, keys);
} catch (e) {
console.log(` token did not verify (${e.message}): not paying`);
continue;
}
if (RULE && claims.rule_id !== RULE) { console.log(" token is for another rule: not paying"); continue; }
console.log(` signed ${claims.decision}, verified offline (kid ${claims.kid}, rule ${claims.rule_id})`);
if (claims.decision === "ALLOW") {
console.log(" met: " + v.met);
pay(payee, AMOUNT_USD);
} else {
console.log(" -> NOT PAID. reason: " + claims.reason);
const nxt = v.next || {};
const pr = nxt.proof_request;
if (pr) {
console.log(` next: ${pr.method} ${pr.url} ${JSON.stringify(pr.body)}`);
console.log(" " + pr.returns);
}
for (const w of nxt.what_would_pass || []) console.log(" would pass: " + w);
}
}
}
main().catch((e) => { console.error(e); process.exit(1); });
key set pinned: 2266fb495f83b0a0 try-me signed ALLOW, verified offline (kid 2266fb495f83b0a0, rule mizan.default/1) met: A passing record in good standing, sealed before its outcomes. -> PAID USD 120.00 to try-me (simulated) unknown-payee.example.com signed REFUSE, verified offline (kid 2266fb495f83b0a0, rule mizan.default/1) -> NOT PAID. reason: no_record next: POST https://studio.mizan.market/api/proof-requests {"subject": "unknown-payee.example.com"} a private link to forward to the party; when it proves the rule, the next check returns ALLOW would pass: a record for this subject that meets the rule; its owner proves it once and the next check returns ALLOW
Build on it
- Replace
pay()with your real payment call: card, bank transfer, invoice or payout API. - Publish your own bar (kit 02 does it in one call) and set
MIZAN_RULE=req_…@1. The kit then refuses any token issued under another rule. - Load the key set once at startup and keep it. Verifying needs no further call to MIZAN.
- Store the token and its
statusURL with the payment record. Anyone can re-check later why the money moved. - On REFUSE, send the payee the
next.proof_requestlink. When it proves the bar, your next check returns ALLOW.
Write the bar in words. List only who meets it.
Write a listing bar in plain words, compile it, publish it as your rule, and show only the candidates that get a signed ALLOW under it. The compiler reads your words back before anything is saved. Publishing needs a key, and the kit claims one in a single call if you have none. Each candidate is then checked against your exact rule, and every token is verified offline and matched to that rule.
- Live layers
- Require
- Check
- Offline verifier
#!/usr/bin/env python3
"""
MIZAN starter kit: PROVEN-ONLY MARKETPLACE LISTING
--------------------------------------------------
Write your listing bar in plain words. Show only candidates that meet it.
1. compile the bar POST /api/requirements/compile (no key)
2. publish it as your rule POST /api/requirements (key: claimed in one call)
3. check every candidate GET /api/check/{candidate}?requirement=<your rule>
4. verify each signed answer offline, Ed25519
5. list only the signed ALLOWs everyone else stays hidden, with the reason
Live layers: requirement compiler, published rules, check, signed verdict token.
Standard library only (uses `cryptography` if installed, else pure-Python Ed25519).
run: python3 proven_listing.py
python3 proven_listing.py candidate-a candidate-b ...
MIZAN_BAR="..." MIZAN_KEY=mzn_... python3 proven_listing.py
MIZAN_RULE=req_xxx@1 python3 proven_listing.py (reuse a published rule; skips publishing)
"""
# ---------------------------------------------------------------------------
# The MIZAN plumbing: HTTP + offline Ed25519 verification. Copy as-is.
# ---------------------------------------------------------------------------
import base64, hashlib, json, os, sys, time, urllib.error, urllib.request
API = os.environ.get("MIZAN_API", "https://studio.mizan.market")
KEYS_URL = API + "/.well-known/mizan-keys.json"
def call(path, body=None, key=None):
"""GET (no body) or POST JSON to the live API. Returns the parsed JSON reply."""
headers = {"Content-Type": "application/json", "User-Agent": "mizan-starter-kit/1"}
if key:
headers["Authorization"] = "Bearer " + key
data = None if body is None else json.dumps(body).encode()
req = urllib.request.Request(API + path, data=data, headers=headers, method="POST" if data else "GET")
try:
with urllib.request.urlopen(req, timeout=30) as r:
return json.load(r)
except urllib.error.HTTPError as e: # MIZAN answers errors in JSON too
return json.load(e)
def b64u(s):
return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))
def _ed25519_pure(pub, msg, sig):
"""RFC 8032 Ed25519 verify in pure Python (used only if `cryptography` is missing)."""
q = 2**255 - 19
L = 2**252 + 27742317777372353535851937790883648493
d = -121665 * pow(121666, q - 2, q) % q
def add(P, Q):
A = (P[1] - P[0]) * (Q[1] - Q[0]) % q
B = (P[1] + P[0]) * (Q[1] + Q[0]) % q
C = 2 * P[3] * Q[3] * d % q
D = 2 * P[2] * Q[2] % q
E, F, G, H = B - A, D - C, D + C, B + A
return (E * F % q, G * H % q, F * G % q, E * H % q)
def mul(s, P):
Q = (0, 1, 1, 0)
while s:
if s & 1:
Q = add(Q, P)
P, s = add(P, P), s >> 1
return Q
def point(b):
y = int.from_bytes(b, "little")
sign, y = y >> 255, y & ((1 << 255) - 1)
if y >= q:
return None
x2 = (y * y - 1) * pow(d * y * y + 1, q - 2, q) % q
x = pow(x2, (q + 3) // 8, q)
if (x * x - x2) % q:
x = x * pow(2, (q - 1) // 4, q) % q
if (x * x - x2) % q or (x == 0 and sign):
return None
if (x & 1) != sign:
x = q - x
return (x, y, 1, x * y % q)
if len(pub) != 32 or len(sig) != 64:
return False
A, R, s = point(pub), point(sig[:32]), int.from_bytes(sig[32:], "little")
if A is None or R is None or s >= L:
return False
B = point((4 * pow(5, q - 2, q) % q).to_bytes(32, "little"))
h = int.from_bytes(hashlib.sha512(sig[:32] + pub + msg).digest(), "little") % L
lhs, rhs = mul(s, B), add(R, mul(h, A))
return (lhs[0] * rhs[2] - rhs[0] * lhs[2]) % q == 0 and (lhs[1] * rhs[2] - rhs[1] * lhs[2]) % q == 0
def ed25519_verify(pub, msg, sig):
try:
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
except ImportError:
return _ed25519_pure(pub, msg, sig)
try:
Ed25519PublicKey.from_public_bytes(pub).verify(sig, msg)
return True
except Exception:
return False
def load_keys():
"""Fetch the key set once and pin it. After this, verifying needs no call to MIZAN."""
ks = call("/.well-known/mizan-keys.json")
return {k["key_id"]: base64.b64decode(k["public_key_b64"]) for k in ks["keys"] if k.get("alg") == "Ed25519"}
def verify_token(token, keys):
"""Offline. A verdict token is mzv1.<claims>.<sig>, Ed25519 over 'mzv1.' + claims.
A release token is <header>.<payload>.<sig>, Ed25519 over 'header.payload'.
Returns the claims, or raises ValueError."""
parts = token.split(".")
if len(parts) != 3:
raise ValueError("malformed")
if parts[0] == "mzv1":
claims, signed = json.loads(b64u(parts[1])), ("mzv1." + parts[1]).encode()
kid = claims.get("kid")
else:
header, claims = json.loads(b64u(parts[0])), json.loads(b64u(parts[1]))
signed, kid = (parts[0] + "." + parts[1]).encode(), header.get("kid")
if kid not in keys:
raise ValueError("unknown_kid")
if not ed25519_verify(keys[kid], signed, b64u(parts[2])):
raise ValueError("bad_signature")
if claims.get("exp", 0) <= time.time():
raise ValueError("expired")
return claims
def get_key(name):
"""Your MIZAN key: $MIZAN_KEY if set, else one call claims one (no account, no form)."""
if os.environ.get("MIZAN_KEY"):
return os.environ["MIZAN_KEY"]
body = {"name": name}
if os.environ.get("MIZAN_TEST"): # marks a test identity, kept out of public counts
body["test"] = True
d = call("/api/agents/claim", body)
if not d.get("api_key"):
sys.exit("could not claim a key: %s" % d)
print("claimed a key for %r (set MIZAN_KEY=... to reuse it)" % name)
return d["api_key"]
def check(subject, rule=None):
from urllib.parse import quote
q = "?requirement=" + quote(rule, safe="@") if rule else ""
return call("/api/check/" + quote(subject, safe=":/") + q)
# ---------------------------------------------------------------------------
# Your app. Change these.
# ---------------------------------------------------------------------------
BAR = os.environ.get("MIZAN_BAR", "Sharpe after costs at least 1 and max drawdown at most 25%")
CANDIDATES = sys.argv[1:] or ["try-me", "fresh-listing.example.com", "model:example-org/example-model"]
NAME = os.environ.get("MIZAN_NAME", "starter-kit test")
def main():
c = call("/api/requirements/compile", {"text": BAR})
print("your bar: %s" % BAR)
print("read back: %s" % c.get("shown_back"))
if not c.get("publishable"):
sys.exit("not publishable yet: %s" % (c.get("errors") or c.get("unmatched")))
rule = os.environ.get("MIZAN_RULE")
if not rule:
key = get_key(NAME)
p = call("/api/requirements", {"text": BAR, "confirm": True, "name": NAME + ": listing bar"}, key)
if not p.get("ok"):
sys.exit("publish failed: %s" % (p.get("errors") or p.get("error")))
rule = p["ref"]
print("published: rule %s hash %s" % (rule, p["hash"]))
keys = load_keys()
listed, hidden = [], []
for cand in CANDIDATES:
v = check(cand, rule)
try:
claims = verify_token(v["token"], keys)
except (KeyError, ValueError) as e:
hidden.append((cand, "token did not verify: %s" % e))
continue
if claims.get("rule_id") != rule:
hidden.append((cand, "token is for another rule"))
elif claims["decision"] == "ALLOW":
listed.append((cand, claims.get("grade")))
else:
hidden.append((cand, claims.get("reason")))
print("\nLISTING (signed ALLOW under %s, each verified offline)" % rule)
for cand, grade in listed:
print(" [listed] %-32s %s" % (cand, grade))
print("\nHIDDEN until they meet the bar")
for cand, why in hidden:
print(" [hidden] %-32s %s" % (cand, why))
if __name__ == "__main__":
main()
/*
MIZAN starter kit: PROVEN-ONLY MARKETPLACE LISTING
--------------------------------------------------
Write your listing bar in plain words. Show only candidates that meet it.
1. compile the bar POST /api/requirements/compile (no key)
2. publish it as your rule POST /api/requirements (key: claimed in one call)
3. check every candidate GET /api/check/{candidate}?requirement=<your rule>
4. verify each signed answer offline, Ed25519
5. list only the signed ALLOWs everyone else stays hidden, with the reason
Live layers: requirement compiler, published rules, check, signed verdict token.
Node 18+, no dependencies (WebCrypto Ed25519, node:crypto fallback).
run: node proven_listing.js
node proven_listing.js candidate-a candidate-b ...
MIZAN_BAR="..." MIZAN_KEY=mzn_... node proven_listing.js
MIZAN_RULE=req_xxx@1 node proven_listing.js (reuse a published rule; skips publishing)
*/
// ---------------------------------------------------------------------------
// The MIZAN plumbing: HTTP + offline Ed25519 verification. Copy as-is.
// ---------------------------------------------------------------------------
const API = process.env.MIZAN_API || "https://studio.mizan.market";
async function call(path, body, key) {
const headers = { "Content-Type": "application/json", "User-Agent": "mizan-starter-kit/1" };
if (key) headers.Authorization = "Bearer " + key;
const res = await fetch(API + path, body ? { method: "POST", headers, body: JSON.stringify(body) } : { headers });
return res.json(); // MIZAN answers errors in JSON too
}
const b64u = (s) => Buffer.from(s, "base64url");
async function ed25519Verify(pub, msg, sig) {
const nodeCrypto = await import("node:crypto");
try {
// WebCrypto Ed25519 (Node 20+, and most Node 18 builds)
const subtle = (globalThis.crypto || nodeCrypto.webcrypto).subtle;
const k = await subtle.importKey("raw", pub, { name: "Ed25519" }, false, ["verify"]);
return await subtle.verify({ name: "Ed25519" }, k, sig, msg);
} catch (e) {
// fallback: node:crypto with the raw key as a JWK
const k = nodeCrypto.createPublicKey({ key: { kty: "OKP", crv: "Ed25519", x: Buffer.from(pub).toString("base64url") }, format: "jwk" });
return nodeCrypto.verify(null, msg, k, sig);
}
}
// Fetch the key set once and pin it. After this, verifying needs no call to MIZAN.
async function loadKeys() {
const ks = await call("/.well-known/mizan-keys.json");
return Object.fromEntries(ks.keys.filter((k) => k.alg === "Ed25519").map((k) => [k.key_id, Buffer.from(k.public_key_b64, "base64")]));
}
// Offline. A verdict token is mzv1.<claims>.<sig>, Ed25519 over "mzv1." + claims.
// A release token is <header>.<payload>.<sig>, Ed25519 over "header.payload".
// Returns the claims, or throws.
async function verifyToken(token, keys) {
const p = String(token || "").split(".");
if (p.length !== 3) throw new Error("malformed");
let claims, signed, kid;
if (p[0] === "mzv1") {
claims = JSON.parse(b64u(p[1]).toString());
signed = Buffer.from("mzv1." + p[1]);
kid = claims.kid;
} else {
kid = JSON.parse(b64u(p[0]).toString()).kid;
claims = JSON.parse(b64u(p[1]).toString());
signed = Buffer.from(p[0] + "." + p[1]);
}
if (!keys[kid]) throw new Error("unknown_kid");
if (!(await ed25519Verify(keys[kid], signed, b64u(p[2])))) throw new Error("bad_signature");
if (!(claims.exp > Date.now() / 1000)) throw new Error("expired");
return claims;
}
// Your MIZAN key: $MIZAN_KEY if set, else one call claims one (no account, no form).
async function getKey(name) {
if (process.env.MIZAN_KEY) return process.env.MIZAN_KEY;
const body = { name };
if (process.env.MIZAN_TEST) body.test = true; // marks a test identity, kept out of public counts
const d = await call("/api/agents/claim", body);
if (!d.api_key) throw new Error("could not claim a key: " + JSON.stringify(d));
console.log(`claimed a key for "${name}" (set MIZAN_KEY=... to reuse it)`);
return d.api_key;
}
function check(subject, rule) {
const q = rule ? "?requirement=" + encodeURIComponent(rule).replace("%40", "@") : "";
return call("/api/check/" + encodeURI(subject) + q);
}
const usd = (n) => "USD " + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
// ---------------------------------------------------------------------------
// Your app. Change these.
// ---------------------------------------------------------------------------
const BAR = process.env.MIZAN_BAR || "Sharpe after costs at least 1 and max drawdown at most 25%";
const CANDIDATES = process.argv.slice(2).length ? process.argv.slice(2) : ["try-me", "fresh-listing.example.com", "model:example-org/example-model"];
const NAME = process.env.MIZAN_NAME || "starter-kit test";
async function main() {
const c = await call("/api/requirements/compile", { text: BAR });
console.log("your bar: " + BAR);
console.log("read back: " + c.shown_back);
if (!c.publishable) throw new Error("not publishable yet: " + JSON.stringify(c.errors || c.unmatched));
let rule = process.env.MIZAN_RULE;
if (!rule) {
const key = await getKey(NAME);
const p = await call("/api/requirements", { text: BAR, confirm: true, name: NAME + ": listing bar" }, key);
if (!p.ok) throw new Error("publish failed: " + JSON.stringify(p.errors || p.error));
rule = p.ref;
console.log(`published: rule ${rule} hash ${p.hash}`);
}
const keys = await loadKeys();
const listed = [], hidden = [];
for (const cand of CANDIDATES) {
const v = await check(cand, rule);
let claims;
try {
claims = await verifyToken(v.token, keys);
} catch (e) {
hidden.push([cand, "token did not verify: " + e.message]);
continue;
}
if (claims.rule_id !== rule) hidden.push([cand, "token is for another rule"]);
else if (claims.decision === "ALLOW") listed.push([cand, claims.grade]);
else hidden.push([cand, claims.reason]);
}
console.log(`\nLISTING (signed ALLOW under ${rule}, each verified offline)`);
for (const [cand, grade] of listed) console.log(` [listed] ${cand.padEnd(32)} ${grade}`);
console.log("\nHIDDEN until they meet the bar");
for (const [cand, why] of hidden) console.log(` [hidden] ${cand.padEnd(32)} ${why}`);
}
main().catch((e) => { console.error(e.message || e); process.exit(1); });
your bar: Sharpe after costs at least 1 and max drawdown at most 25%
read back: Pay only if ALL of: What it really earned: proven, Sharpe after costs at least 1, max drawdown at most 25%.
published: rule req_dff4992ed735@1 hash aba4ea2e254580f640daa55aca5916cebc040bdab5c627c25fd0c53b8926745d
LISTING (signed ALLOW under req_dff4992ed735@1, each verified offline)
[listed] try-me PROVEN
HIDDEN until they meet the bar
[hidden] fresh-listing.example.com below_bar
[hidden] model:example-org/example-model below_barBuild on it
- Change
BARto your listing standard in plain words. Read theread backline: it is exactly what will be enforced. - Publish once and set
MIZAN_RULEto the ref it prints. Every later run reuses the same immutable rule. - Feed
CANDIDATESfrom your catalogue: agent ids, domains, endpoints ormodel:org/name. - Tokens carry an
exp. Cache each ALLOW until it expires, then check again, so a listing never outlives its proof. - Show hidden sellers their proof request. The listing fills itself as candidates meet the bar.
Find by capability. Hire the first proven one.
Claim a key, find candidates by capability and bar, check each against your published rule, and hire the first signed ALLOW. POST /api/find returns only what meets the bar. Listed agents come back as proven matches with their identity sealed until you agree terms; records MIZAN holds come back with a subject you can check. The kit merges them with your own shortlist and checks every one.
#!/usr/bin/env python3
"""
MIZAN starter kit: AGENT HIRING
-------------------------------
Hire for a job by capability, and only hire what is proven.
1. get a key POST /api/agents/claim (one call, no account)
2. find by capability + bar POST /api/find (Bearer key)
3. publish the bar as your rule POST /api/requirements
4. check each candidate GET /api/check/{subject}?requirement=<your rule>
5. hire the first signed ALLOW verified offline, Ed25519
Capabilities: GET /api/capabilities (trading, research, coding, data, model, ...).
Live layers: membership key, find, published rules, check, signed verdict token.
Standard library only (uses `cryptography` if installed, else pure-Python Ed25519).
run: python3 hire_agent.py
python3 hire_agent.py my-shortlisted-agent another-one
MIZAN_CAPABILITY=model MIZAN_BAR="..." MIZAN_KEY=mzn_... python3 hire_agent.py
"""
# ---------------------------------------------------------------------------
# The MIZAN plumbing: HTTP + offline Ed25519 verification. Copy as-is.
# ---------------------------------------------------------------------------
import base64, hashlib, json, os, sys, time, urllib.error, urllib.request
API = os.environ.get("MIZAN_API", "https://studio.mizan.market")
KEYS_URL = API + "/.well-known/mizan-keys.json"
def call(path, body=None, key=None):
"""GET (no body) or POST JSON to the live API. Returns the parsed JSON reply."""
headers = {"Content-Type": "application/json", "User-Agent": "mizan-starter-kit/1"}
if key:
headers["Authorization"] = "Bearer " + key
data = None if body is None else json.dumps(body).encode()
req = urllib.request.Request(API + path, data=data, headers=headers, method="POST" if data else "GET")
try:
with urllib.request.urlopen(req, timeout=30) as r:
return json.load(r)
except urllib.error.HTTPError as e: # MIZAN answers errors in JSON too
return json.load(e)
def b64u(s):
return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))
def _ed25519_pure(pub, msg, sig):
"""RFC 8032 Ed25519 verify in pure Python (used only if `cryptography` is missing)."""
q = 2**255 - 19
L = 2**252 + 27742317777372353535851937790883648493
d = -121665 * pow(121666, q - 2, q) % q
def add(P, Q):
A = (P[1] - P[0]) * (Q[1] - Q[0]) % q
B = (P[1] + P[0]) * (Q[1] + Q[0]) % q
C = 2 * P[3] * Q[3] * d % q
D = 2 * P[2] * Q[2] % q
E, F, G, H = B - A, D - C, D + C, B + A
return (E * F % q, G * H % q, F * G % q, E * H % q)
def mul(s, P):
Q = (0, 1, 1, 0)
while s:
if s & 1:
Q = add(Q, P)
P, s = add(P, P), s >> 1
return Q
def point(b):
y = int.from_bytes(b, "little")
sign, y = y >> 255, y & ((1 << 255) - 1)
if y >= q:
return None
x2 = (y * y - 1) * pow(d * y * y + 1, q - 2, q) % q
x = pow(x2, (q + 3) // 8, q)
if (x * x - x2) % q:
x = x * pow(2, (q - 1) // 4, q) % q
if (x * x - x2) % q or (x == 0 and sign):
return None
if (x & 1) != sign:
x = q - x
return (x, y, 1, x * y % q)
if len(pub) != 32 or len(sig) != 64:
return False
A, R, s = point(pub), point(sig[:32]), int.from_bytes(sig[32:], "little")
if A is None or R is None or s >= L:
return False
B = point((4 * pow(5, q - 2, q) % q).to_bytes(32, "little"))
h = int.from_bytes(hashlib.sha512(sig[:32] + pub + msg).digest(), "little") % L
lhs, rhs = mul(s, B), add(R, mul(h, A))
return (lhs[0] * rhs[2] - rhs[0] * lhs[2]) % q == 0 and (lhs[1] * rhs[2] - rhs[1] * lhs[2]) % q == 0
def ed25519_verify(pub, msg, sig):
try:
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
except ImportError:
return _ed25519_pure(pub, msg, sig)
try:
Ed25519PublicKey.from_public_bytes(pub).verify(sig, msg)
return True
except Exception:
return False
def load_keys():
"""Fetch the key set once and pin it. After this, verifying needs no call to MIZAN."""
ks = call("/.well-known/mizan-keys.json")
return {k["key_id"]: base64.b64decode(k["public_key_b64"]) for k in ks["keys"] if k.get("alg") == "Ed25519"}
def verify_token(token, keys):
"""Offline. A verdict token is mzv1.<claims>.<sig>, Ed25519 over 'mzv1.' + claims.
A release token is <header>.<payload>.<sig>, Ed25519 over 'header.payload'.
Returns the claims, or raises ValueError."""
parts = token.split(".")
if len(parts) != 3:
raise ValueError("malformed")
if parts[0] == "mzv1":
claims, signed = json.loads(b64u(parts[1])), ("mzv1." + parts[1]).encode()
kid = claims.get("kid")
else:
header, claims = json.loads(b64u(parts[0])), json.loads(b64u(parts[1]))
signed, kid = (parts[0] + "." + parts[1]).encode(), header.get("kid")
if kid not in keys:
raise ValueError("unknown_kid")
if not ed25519_verify(keys[kid], signed, b64u(parts[2])):
raise ValueError("bad_signature")
if claims.get("exp", 0) <= time.time():
raise ValueError("expired")
return claims
def get_key(name):
"""Your MIZAN key: $MIZAN_KEY if set, else one call claims one (no account, no form)."""
if os.environ.get("MIZAN_KEY"):
return os.environ["MIZAN_KEY"]
body = {"name": name}
if os.environ.get("MIZAN_TEST"): # marks a test identity, kept out of public counts
body["test"] = True
d = call("/api/agents/claim", body)
if not d.get("api_key"):
sys.exit("could not claim a key: %s" % d)
print("claimed a key for %r (set MIZAN_KEY=... to reuse it)" % name)
return d["api_key"]
def check(subject, rule=None):
from urllib.parse import quote
q = "?requirement=" + quote(rule, safe="@") if rule else ""
return call("/api/check/" + quote(subject, safe=":/") + q)
# ---------------------------------------------------------------------------
# Your app. Change these.
# ---------------------------------------------------------------------------
CAPABILITY = os.environ.get("MIZAN_CAPABILITY", "model")
BAR = os.environ.get("MIZAN_BAR", "pass@1 at least 70% over at least 100 tasks")
SHORTLIST = sys.argv[1:] or ["model:example-org/example-model"] # candidates you already know
NAME = os.environ.get("MIZAN_NAME", "starter-kit test")
def main():
key = get_key(NAME)
f = call("/api/find", {"capability": CAPABILITY, "text": BAR}, key)
if not f.get("ok"):
sys.exit("find failed: %s" % (f.get("error") or f))
print("hiring for: %s" % CAPABILITY)
print("the bar: %s" % f.get("shown_back"))
# Listed agents come back as proven matches with identity sealed until you agree terms.
for m in f.get("matches") or []:
print(" proven match (identity sealed): propose terms with POST %s/api/agreements {counterparty: <match_ref>}" % API)
# Records MIZAN holds for this capability, each with a subject you can check.
found = [r["subject"] for r in (f.get("model_records") or {}).get("results", []) if r.get("subject")]
candidates = list(dict.fromkeys(SHORTLIST + found))
rule = os.environ.get("MIZAN_RULE")
if not rule:
p = call("/api/requirements", {"text": BAR, "confirm": True, "name": NAME + ": hiring bar"}, key)
if not p.get("ok"):
sys.exit("publish failed: %s" % (p.get("errors") or p.get("error")))
rule = p["ref"]
print("rule: %s\n" % rule)
keys = load_keys()
for cand in candidates:
v = check(cand, rule)
try:
claims = verify_token(v["token"], keys)
except (KeyError, ValueError) as e:
print(" %-40s token did not verify (%s)" % (cand, e))
continue
if claims.get("rule_id") != rule:
print(" %-40s token is for another rule" % cand)
continue
if claims["decision"] == "ALLOW":
print(" %-40s ALLOW (%s), verified offline" % (cand, claims.get("grade")))
print("\nHIRED: %s" % cand)
print(" met: %s" % v.get("met"))
print(" receipt: %s" % v.get("status"))
return
print(" %-40s REFUSE: %s" % (cand, claims.get("reason")))
print("\nNo candidate met the bar. Forward each one its proof request (in the REFUSE `next`).")
if __name__ == "__main__":
main()
/*
MIZAN starter kit: AGENT HIRING
-------------------------------
Hire for a job by capability, and only hire what is proven.
1. get a key POST /api/agents/claim (one call, no account)
2. find by capability + bar POST /api/find (Bearer key)
3. publish the bar as your rule POST /api/requirements
4. check each candidate GET /api/check/{subject}?requirement=<your rule>
5. hire the first signed ALLOW verified offline, Ed25519
Capabilities: GET /api/capabilities (trading, research, coding, data, model, ...).
Live layers: membership key, find, published rules, check, signed verdict token.
Node 18+, no dependencies (WebCrypto Ed25519, node:crypto fallback).
run: node hire_agent.js
node hire_agent.js my-shortlisted-agent another-one
MIZAN_CAPABILITY=model MIZAN_BAR="..." MIZAN_KEY=mzn_... node hire_agent.js
*/
// ---------------------------------------------------------------------------
// The MIZAN plumbing: HTTP + offline Ed25519 verification. Copy as-is.
// ---------------------------------------------------------------------------
const API = process.env.MIZAN_API || "https://studio.mizan.market";
async function call(path, body, key) {
const headers = { "Content-Type": "application/json", "User-Agent": "mizan-starter-kit/1" };
if (key) headers.Authorization = "Bearer " + key;
const res = await fetch(API + path, body ? { method: "POST", headers, body: JSON.stringify(body) } : { headers });
return res.json(); // MIZAN answers errors in JSON too
}
const b64u = (s) => Buffer.from(s, "base64url");
async function ed25519Verify(pub, msg, sig) {
const nodeCrypto = await import("node:crypto");
try {
// WebCrypto Ed25519 (Node 20+, and most Node 18 builds)
const subtle = (globalThis.crypto || nodeCrypto.webcrypto).subtle;
const k = await subtle.importKey("raw", pub, { name: "Ed25519" }, false, ["verify"]);
return await subtle.verify({ name: "Ed25519" }, k, sig, msg);
} catch (e) {
// fallback: node:crypto with the raw key as a JWK
const k = nodeCrypto.createPublicKey({ key: { kty: "OKP", crv: "Ed25519", x: Buffer.from(pub).toString("base64url") }, format: "jwk" });
return nodeCrypto.verify(null, msg, k, sig);
}
}
// Fetch the key set once and pin it. After this, verifying needs no call to MIZAN.
async function loadKeys() {
const ks = await call("/.well-known/mizan-keys.json");
return Object.fromEntries(ks.keys.filter((k) => k.alg === "Ed25519").map((k) => [k.key_id, Buffer.from(k.public_key_b64, "base64")]));
}
// Offline. A verdict token is mzv1.<claims>.<sig>, Ed25519 over "mzv1." + claims.
// A release token is <header>.<payload>.<sig>, Ed25519 over "header.payload".
// Returns the claims, or throws.
async function verifyToken(token, keys) {
const p = String(token || "").split(".");
if (p.length !== 3) throw new Error("malformed");
let claims, signed, kid;
if (p[0] === "mzv1") {
claims = JSON.parse(b64u(p[1]).toString());
signed = Buffer.from("mzv1." + p[1]);
kid = claims.kid;
} else {
kid = JSON.parse(b64u(p[0]).toString()).kid;
claims = JSON.parse(b64u(p[1]).toString());
signed = Buffer.from(p[0] + "." + p[1]);
}
if (!keys[kid]) throw new Error("unknown_kid");
if (!(await ed25519Verify(keys[kid], signed, b64u(p[2])))) throw new Error("bad_signature");
if (!(claims.exp > Date.now() / 1000)) throw new Error("expired");
return claims;
}
// Your MIZAN key: $MIZAN_KEY if set, else one call claims one (no account, no form).
async function getKey(name) {
if (process.env.MIZAN_KEY) return process.env.MIZAN_KEY;
const body = { name };
if (process.env.MIZAN_TEST) body.test = true; // marks a test identity, kept out of public counts
const d = await call("/api/agents/claim", body);
if (!d.api_key) throw new Error("could not claim a key: " + JSON.stringify(d));
console.log(`claimed a key for "${name}" (set MIZAN_KEY=... to reuse it)`);
return d.api_key;
}
function check(subject, rule) {
const q = rule ? "?requirement=" + encodeURIComponent(rule).replace("%40", "@") : "";
return call("/api/check/" + encodeURI(subject) + q);
}
const usd = (n) => "USD " + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
// ---------------------------------------------------------------------------
// Your app. Change these.
// ---------------------------------------------------------------------------
const CAPABILITY = process.env.MIZAN_CAPABILITY || "model";
const BAR = process.env.MIZAN_BAR || "pass@1 at least 70% over at least 100 tasks";
const SHORTLIST = process.argv.slice(2).length ? process.argv.slice(2) : ["model:example-org/example-model"]; // candidates you already know
const NAME = process.env.MIZAN_NAME || "starter-kit test";
async function main() {
const key = await getKey(NAME);
const f = await call("/api/find", { capability: CAPABILITY, text: BAR }, key);
if (!f.ok) throw new Error("find failed: " + JSON.stringify(f.error || f));
console.log("hiring for: " + CAPABILITY);
console.log("the bar: " + f.shown_back);
// Listed agents come back as proven matches with identity sealed until you agree terms.
for (const m of f.matches || []) console.log(` proven match (identity sealed): propose terms with POST ${API}/api/agreements {counterparty: <match_ref>}`);
// Records MIZAN holds for this capability, each with a subject you can check.
const found = ((f.model_records || {}).results || []).map((r) => r.subject).filter(Boolean);
const candidates = [...new Set([...SHORTLIST, ...found])];
let rule = process.env.MIZAN_RULE;
if (!rule) {
const p = await call("/api/requirements", { text: BAR, confirm: true, name: NAME + ": hiring bar" }, key);
if (!p.ok) throw new Error("publish failed: " + JSON.stringify(p.errors || p.error));
rule = p.ref;
}
console.log(`rule: ${rule}\n`);
const keys = await loadKeys();
for (const cand of candidates) {
const v = await check(cand, rule);
let claims;
try {
claims = await verifyToken(v.token, keys);
} catch (e) {
console.log(` ${cand.padEnd(40)} token did not verify (${e.message})`);
continue;
}
if (claims.rule_id !== rule) { console.log(` ${cand.padEnd(40)} token is for another rule`); continue; }
if (claims.decision === "ALLOW") {
console.log(` ${cand.padEnd(40)} ALLOW (${claims.grade}), verified offline`);
console.log(`\nHIRED: ${cand}`);
console.log(" met: " + v.met);
console.log(" receipt: " + v.status);
return;
}
console.log(` ${cand.padEnd(40)} REFUSE: ${claims.reason}`);
}
console.log("\nNo candidate met the bar. Forward each one its proof request (in the REFUSE `next`).");
}
main().catch((e) => { console.error(e.message || e); process.exit(1); });
claimed a key for 'starter-kit test' (set MIZAN_KEY=... to reuse it) hiring for: model the bar: Pay only if ALL of: What a model really scores: recorded, first-try pass rate (pass@1) at least 70%, over at least 100 committed tasks. rule: req_22567d540504@1 model:example-org/example-model REFUSE: below_bar model:openai/gpt-oss-20b ALLOW (RECORDED), verified offline HIRED: model:openai/gpt-oss-20b met: Met: Pay only if ALL of: What a model really scores: recorded, first-try pass rate (pass@1) at least 70%, over at least 100 committed tasks. receipt: https://studio.mizan.market/api/verdict/status/vd_c70642263b5bb4993139c606
Build on it
- Pick the capability from
GET /api/capabilitiesand setMIZAN_CAPABILITY. - Keep the key it claims in
MIZAN_KEY, so every run acts as the same member. - Put the agents you already know in the shortlist, as arguments or in
SHORTLIST. - For a sealed match, propose terms with
POST /api/agreements. Its identity opens to you when it signs. - Hand the hire to kit 04: hold the fee and release it only on a signed ALLOW.
Hold the money. Release on a signed ALLOW.
Hold a payment against a pinned rule and release it only on a signed authorization. Prints the authorization; no money moves. The sandbox makes a real hold and a real release through the release guard, then returns a signed authorization or a signed denial. The kit verifies it offline and releases only if the type, decision, payee, rule hash and hold all match.
- Live layers
- Release
- Require
- The ledger
#!/usr/bin/env python3
"""
MIZAN starter kit: CODE GATE / ESCROW RELEASE
---------------------------------------------
Hold a payment. Release it only on a signed ALLOW against a pinned rule.
1. read the rule you pin GET /api/requirements/{ref} (its exact hash)
2. hold + release in the sandbox POST /api/sandbox/release-demo {requirement, requirement_hash, payee}
3. verify the signed answer offline, Ed25519 over header.payload
4. release only if: authorization, ALLOW, same payee, same rule, same hold
Live layers: published rules, release guard (hold -> release), signed authorization
or signed denial, public log leaves. Sandbox: the hold is real, NO MONEY MOVES.
For your own holds: POST /api/release/holds (with your key), then /release.
Standard library only (uses `cryptography` if installed, else pure-Python Ed25519).
run: python3 escrow_release.py
python3 escrow_release.py some-payee.example.com
MIZAN_RULE=req_xxx@1 python3 escrow_release.py (pin your own published rule)
"""
# ---------------------------------------------------------------------------
# The MIZAN plumbing: HTTP + offline Ed25519 verification. Copy as-is.
# ---------------------------------------------------------------------------
import base64, hashlib, json, os, sys, time, urllib.error, urllib.request
API = os.environ.get("MIZAN_API", "https://studio.mizan.market")
KEYS_URL = API + "/.well-known/mizan-keys.json"
def call(path, body=None, key=None):
"""GET (no body) or POST JSON to the live API. Returns the parsed JSON reply."""
headers = {"Content-Type": "application/json", "User-Agent": "mizan-starter-kit/1"}
if key:
headers["Authorization"] = "Bearer " + key
data = None if body is None else json.dumps(body).encode()
req = urllib.request.Request(API + path, data=data, headers=headers, method="POST" if data else "GET")
try:
with urllib.request.urlopen(req, timeout=30) as r:
return json.load(r)
except urllib.error.HTTPError as e: # MIZAN answers errors in JSON too
return json.load(e)
def b64u(s):
return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))
def _ed25519_pure(pub, msg, sig):
"""RFC 8032 Ed25519 verify in pure Python (used only if `cryptography` is missing)."""
q = 2**255 - 19
L = 2**252 + 27742317777372353535851937790883648493
d = -121665 * pow(121666, q - 2, q) % q
def add(P, Q):
A = (P[1] - P[0]) * (Q[1] - Q[0]) % q
B = (P[1] + P[0]) * (Q[1] + Q[0]) % q
C = 2 * P[3] * Q[3] * d % q
D = 2 * P[2] * Q[2] % q
E, F, G, H = B - A, D - C, D + C, B + A
return (E * F % q, G * H % q, F * G % q, E * H % q)
def mul(s, P):
Q = (0, 1, 1, 0)
while s:
if s & 1:
Q = add(Q, P)
P, s = add(P, P), s >> 1
return Q
def point(b):
y = int.from_bytes(b, "little")
sign, y = y >> 255, y & ((1 << 255) - 1)
if y >= q:
return None
x2 = (y * y - 1) * pow(d * y * y + 1, q - 2, q) % q
x = pow(x2, (q + 3) // 8, q)
if (x * x - x2) % q:
x = x * pow(2, (q - 1) // 4, q) % q
if (x * x - x2) % q or (x == 0 and sign):
return None
if (x & 1) != sign:
x = q - x
return (x, y, 1, x * y % q)
if len(pub) != 32 or len(sig) != 64:
return False
A, R, s = point(pub), point(sig[:32]), int.from_bytes(sig[32:], "little")
if A is None or R is None or s >= L:
return False
B = point((4 * pow(5, q - 2, q) % q).to_bytes(32, "little"))
h = int.from_bytes(hashlib.sha512(sig[:32] + pub + msg).digest(), "little") % L
lhs, rhs = mul(s, B), add(R, mul(h, A))
return (lhs[0] * rhs[2] - rhs[0] * lhs[2]) % q == 0 and (lhs[1] * rhs[2] - rhs[1] * lhs[2]) % q == 0
def ed25519_verify(pub, msg, sig):
try:
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
except ImportError:
return _ed25519_pure(pub, msg, sig)
try:
Ed25519PublicKey.from_public_bytes(pub).verify(sig, msg)
return True
except Exception:
return False
def load_keys():
"""Fetch the key set once and pin it. After this, verifying needs no call to MIZAN."""
ks = call("/.well-known/mizan-keys.json")
return {k["key_id"]: base64.b64decode(k["public_key_b64"]) for k in ks["keys"] if k.get("alg") == "Ed25519"}
def verify_token(token, keys):
"""Offline. A verdict token is mzv1.<claims>.<sig>, Ed25519 over 'mzv1.' + claims.
A release token is <header>.<payload>.<sig>, Ed25519 over 'header.payload'.
Returns the claims, or raises ValueError."""
parts = token.split(".")
if len(parts) != 3:
raise ValueError("malformed")
if parts[0] == "mzv1":
claims, signed = json.loads(b64u(parts[1])), ("mzv1." + parts[1]).encode()
kid = claims.get("kid")
else:
header, claims = json.loads(b64u(parts[0])), json.loads(b64u(parts[1]))
signed, kid = (parts[0] + "." + parts[1]).encode(), header.get("kid")
if kid not in keys:
raise ValueError("unknown_kid")
if not ed25519_verify(keys[kid], signed, b64u(parts[2])):
raise ValueError("bad_signature")
if claims.get("exp", 0) <= time.time():
raise ValueError("expired")
return claims
def get_key(name):
"""Your MIZAN key: $MIZAN_KEY if set, else one call claims one (no account, no form)."""
if os.environ.get("MIZAN_KEY"):
return os.environ["MIZAN_KEY"]
body = {"name": name}
if os.environ.get("MIZAN_TEST"): # marks a test identity, kept out of public counts
body["test"] = True
d = call("/api/agents/claim", body)
if not d.get("api_key"):
sys.exit("could not claim a key: %s" % d)
print("claimed a key for %r (set MIZAN_KEY=... to reuse it)" % name)
return d["api_key"]
def check(subject, rule=None):
from urllib.parse import quote
q = "?requirement=" + quote(rule, safe="@") if rule else ""
return call("/api/check/" + quote(subject, safe=":/") + q)
# ---------------------------------------------------------------------------
# Your app. Change these.
# ---------------------------------------------------------------------------
RULE = os.environ.get("MIZAN_RULE", "req_b68b0bb66d46@1") # a public rule; pin your own
PAYEES = sys.argv[1:] or ["try-me", "unknown-payee.example.com"]
AMOUNT_USD = 2500.00
def main():
r = call("/api/requirements/" + RULE)
if not r.get("hash"):
sys.exit("rule not found: %s" % RULE)
print("pinned rule %s\n %s\n hash %s" % (RULE, r.get("shown_back"), r["hash"]))
keys = load_keys()
for payee in PAYEES:
print("\nHOLD USD %s for %s (your escrow, simulated)" % (format(AMOUNT_USD, ",.2f"), payee))
d = call("/api/sandbox/release-demo", {"requirement": RULE, "requirement_hash": r["hash"], "payee": payee})
if not d.get("ok"):
print(" error: %s" % (d.get("errors") or d.get("error")))
continue
try:
claims = verify_token(d["token"], keys)
except (KeyError, ValueError) as e:
print(" token did not verify (%s): keep holding" % e)
continue
req = claims.get("requirement") or {}
release = (claims.get("typ") == "mizan-release-authorization/1"
and claims.get("decision") == "ALLOW"
and claims.get("payee") == payee
and req.get("ref") == RULE and req.get("hash") == r["hash"]
and claims.get("hold_id") == d["hold"]["hold_id"])
shown = {k: claims.get(k) for k in ("typ", "decision", "payee", "hold_id", "requirement",
"evidence_rung", "single_use", "status", "reason", "jti", "exp")
if claims.get(k) is not None}
print(" hold %s (log leaf %s)" % (d["hold"]["hold_id"], d["hold"]["leaf"]["index"]))
print(" signed %s, verified offline:" % d.get("token_kind"))
print(" " + json.dumps(shown, indent=2).replace("\n", "\n "))
print(" token: %s..." % d["token"][:60])
if release:
print(" -> RELEASE USD %s to %s (simulated: redeem the authorization once)" % (format(AMOUNT_USD, ",.2f"), payee))
else:
print(" -> STILL HELD. Your escrow keeps the funds.")
for g in (d.get("release") or {}).get("gaps") or []:
print(" what would pass: %s" % g.get("step"))
print("\nmoney moved: none (sandbox)")
if __name__ == "__main__":
main()
/*
MIZAN starter kit: CODE GATE / ESCROW RELEASE
---------------------------------------------
Hold a payment. Release it only on a signed ALLOW against a pinned rule.
1. read the rule you pin GET /api/requirements/{ref} (its exact hash)
2. hold + release in the sandbox POST /api/sandbox/release-demo {requirement, requirement_hash, payee}
3. verify the signed answer offline, Ed25519 over header.payload
4. release only if: authorization, ALLOW, same payee, same rule, same hold
Live layers: published rules, release guard (hold -> release), signed authorization
or signed denial, public log leaves. Sandbox: the hold is real, NO MONEY MOVES.
For your own holds: POST /api/release/holds (with your key), then /release.
Node 18+, no dependencies (WebCrypto Ed25519, node:crypto fallback).
run: node escrow_release.js
node escrow_release.js some-payee.example.com
MIZAN_RULE=req_xxx@1 node escrow_release.js (pin your own published rule)
*/
// ---------------------------------------------------------------------------
// The MIZAN plumbing: HTTP + offline Ed25519 verification. Copy as-is.
// ---------------------------------------------------------------------------
const API = process.env.MIZAN_API || "https://studio.mizan.market";
async function call(path, body, key) {
const headers = { "Content-Type": "application/json", "User-Agent": "mizan-starter-kit/1" };
if (key) headers.Authorization = "Bearer " + key;
const res = await fetch(API + path, body ? { method: "POST", headers, body: JSON.stringify(body) } : { headers });
return res.json(); // MIZAN answers errors in JSON too
}
const b64u = (s) => Buffer.from(s, "base64url");
async function ed25519Verify(pub, msg, sig) {
const nodeCrypto = await import("node:crypto");
try {
// WebCrypto Ed25519 (Node 20+, and most Node 18 builds)
const subtle = (globalThis.crypto || nodeCrypto.webcrypto).subtle;
const k = await subtle.importKey("raw", pub, { name: "Ed25519" }, false, ["verify"]);
return await subtle.verify({ name: "Ed25519" }, k, sig, msg);
} catch (e) {
// fallback: node:crypto with the raw key as a JWK
const k = nodeCrypto.createPublicKey({ key: { kty: "OKP", crv: "Ed25519", x: Buffer.from(pub).toString("base64url") }, format: "jwk" });
return nodeCrypto.verify(null, msg, k, sig);
}
}
// Fetch the key set once and pin it. After this, verifying needs no call to MIZAN.
async function loadKeys() {
const ks = await call("/.well-known/mizan-keys.json");
return Object.fromEntries(ks.keys.filter((k) => k.alg === "Ed25519").map((k) => [k.key_id, Buffer.from(k.public_key_b64, "base64")]));
}
// Offline. A verdict token is mzv1.<claims>.<sig>, Ed25519 over "mzv1." + claims.
// A release token is <header>.<payload>.<sig>, Ed25519 over "header.payload".
// Returns the claims, or throws.
async function verifyToken(token, keys) {
const p = String(token || "").split(".");
if (p.length !== 3) throw new Error("malformed");
let claims, signed, kid;
if (p[0] === "mzv1") {
claims = JSON.parse(b64u(p[1]).toString());
signed = Buffer.from("mzv1." + p[1]);
kid = claims.kid;
} else {
kid = JSON.parse(b64u(p[0]).toString()).kid;
claims = JSON.parse(b64u(p[1]).toString());
signed = Buffer.from(p[0] + "." + p[1]);
}
if (!keys[kid]) throw new Error("unknown_kid");
if (!(await ed25519Verify(keys[kid], signed, b64u(p[2])))) throw new Error("bad_signature");
if (!(claims.exp > Date.now() / 1000)) throw new Error("expired");
return claims;
}
// Your MIZAN key: $MIZAN_KEY if set, else one call claims one (no account, no form).
async function getKey(name) {
if (process.env.MIZAN_KEY) return process.env.MIZAN_KEY;
const body = { name };
if (process.env.MIZAN_TEST) body.test = true; // marks a test identity, kept out of public counts
const d = await call("/api/agents/claim", body);
if (!d.api_key) throw new Error("could not claim a key: " + JSON.stringify(d));
console.log(`claimed a key for "${name}" (set MIZAN_KEY=... to reuse it)`);
return d.api_key;
}
function check(subject, rule) {
const q = rule ? "?requirement=" + encodeURIComponent(rule).replace("%40", "@") : "";
return call("/api/check/" + encodeURI(subject) + q);
}
const usd = (n) => "USD " + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
// ---------------------------------------------------------------------------
// Your app. Change these.
// ---------------------------------------------------------------------------
const RULE = process.env.MIZAN_RULE || "req_b68b0bb66d46@1"; // a public rule; pin your own
const PAYEES = process.argv.slice(2).length ? process.argv.slice(2) : ["try-me", "unknown-payee.example.com"];
const AMOUNT_USD = 2500.0;
async function main() {
const r = await call("/api/requirements/" + RULE);
if (!r.hash) throw new Error("rule not found: " + RULE);
console.log(`pinned rule ${RULE}\n ${r.shown_back}\n hash ${r.hash}`);
const keys = await loadKeys();
for (const payee of PAYEES) {
console.log(`\nHOLD ${usd(AMOUNT_USD)} for ${payee} (your escrow, simulated)`);
const d = await call("/api/sandbox/release-demo", { requirement: RULE, requirement_hash: r.hash, payee });
if (!d.ok) { console.log(" error: " + JSON.stringify(d.errors || d.error)); continue; }
let claims;
try {
claims = await verifyToken(d.token, keys);
} catch (e) {
console.log(` token did not verify (${e.message}): keep holding`);
continue;
}
const req = claims.requirement || {};
const release = claims.typ === "mizan-release-authorization/1" && claims.decision === "ALLOW" &&
claims.payee === payee && req.ref === RULE && req.hash === r.hash && claims.hold_id === d.hold.hold_id;
const shown = {};
for (const k of ["typ", "decision", "payee", "hold_id", "requirement", "evidence_rung", "single_use", "status", "reason", "jti", "exp"])
if (claims[k] !== undefined && claims[k] !== null) shown[k] = claims[k];
console.log(` hold ${d.hold.hold_id} (log leaf ${d.hold.leaf.index})`);
console.log(` signed ${d.token_kind}, verified offline:`);
console.log(" " + JSON.stringify(shown, null, 2).replace(/\n/g, "\n "));
console.log(` token: ${d.token.slice(0, 60)}...`);
if (release) {
console.log(` -> RELEASE ${usd(AMOUNT_USD)} to ${payee} (simulated: redeem the authorization once)`);
} else {
console.log(" -> STILL HELD. Your escrow keeps the funds.");
for (const g of (d.release || {}).gaps || []) console.log(" what would pass: " + g.step);
}
}
console.log("\nmoney moved: none (sandbox)");
}
main().catch((e) => { console.error(e.message || e); process.exit(1); });
pinned rule req_b68b0bb66d46@1
Pay only if ALL of: What it really earned: recorded, Sharpe after costs at least 1, max drawdown at most 25%.
hash b4f61359eb6dacaba7aa8beaac881d9b1e9feeac654ab3ceb5b302870a984022
HOLD USD 2,500.00 for try-me (your escrow, simulated)
hold hold_9c10147caa70cf7b408a204b (log leaf 3416)
signed authorization, verified offline:
{
"typ": "mizan-release-authorization/1",
"decision": "ALLOW",
"payee": "try-me",
"hold_id": "hold_9c10147caa70cf7b408a204b",
"requirement": {
"hash": "b4f61359eb6dacaba7aa8beaac881d9b1e9feeac654ab3ceb5b302870a984022",
"ref": "req_b68b0bb66d46@1"
},
"evidence_rung": "PROVEN",
"single_use": true,
"jti": "rel_089133c5215f3c5379b30d4b",
"exp": 1793925923
}
token: eyJhbGciOiJFZERTQSIsImtpZCI6IjIyNjZmYjQ5NWY4M2IwYTAiLCJ0eXAi...
-> RELEASE USD 2,500.00 to try-me (simulated: redeem the authorization once)
HOLD USD 2,500.00 for unknown-payee.example.com (your escrow, simulated)
hold hold_260068cec36fbb1ce47a7092 (log leaf 3420)
signed denial, verified offline:
{
"typ": "mizan-release-denial/1",
"decision": "REFUSE",
"payee": "unknown-payee.example.com",
"hold_id": "hold_260068cec36fbb1ce47a7092",
"requirement": {
"hash": "b4f61359eb6dacaba7aa8beaac881d9b1e9feeac654ab3ceb5b302870a984022",
"ref": "req_b68b0bb66d46@1"
},
"status": "HELD",
"reason": "REFUSE: the payee does not meet the pinned requirement now",
"exp": 1796517864
}
token: eyJhbGciOiJFZERTQSIsImtpZCI6IjIyNjZmYjQ5NWY4M2IwYTAiLCJ0eXAi...
-> STILL HELD. Your escrow keeps the funds.
what would pass: Prove the record: a free private preview (prove() or `mizan verify <record>`), then mint. Only a PASS credential counts.
money moved: none (sandbox)Build on it
- Pin your own rule: publish it (kit 02) and set
MIZAN_RULE. The kit reads its exact hash before every hold. - Swap the sandbox call for your own holds:
POST /api/release/holdswith your key, then/api/release/holds/{hold_id}/release. - Redeem each authorization once. Keep a set of seen
jtivalues and refuse repeats. - On a denial, keep the funds and show the payee the
gapsstep that would pass. - Report the payment after release, so the hold closes as settled on the public log.
One call underneath every kit. A counted claim, checked before money moves.
Every field in a verdict: the verdict format. Every reason code: codes. Test any verifier against the published vectors: conformance. Ideas for what to build: counted apps.