Skip to main content

Schema, JCS canonicalization, and EIP-191 signing for verdict envelopes (deterministic outcome attestations).

Project description

verdict-protocol

CI License: MIT Python 3.10+

Schema, JCS canonicalization, and EIP-191 signing for verdict envelopes — the deterministic post-flight attestations produced by agentshield-mcp's outcome evaluator.

This package is a pure library. It defines the wire format, hashes it, and signs it. It does not talk to the network, does not persist anything, and does not manage keys. All of those concerns live in the calling system (see POSITIONING.md for the dual-license context: this MIT package is the wedge; the hosted evaluator and managed-key service are separate).

Install

pip install verdict-protocol

Quickstart

from eth_account import Account
from verdict_protocol import (
    Claim, Envelope, Verdict,
    canonicalize, keccak256,
    output_digest, params_digest,
    sign, verify,
)
from verdict_protocol.schema import utcnow_iso

# 1. The agent describes what it's about to do.
params = {"pair": "ETH/USDC", "amount_in": "1.0", "min_out": "3500.0", "chain_id": 8453}
claim = Claim(
    agent_id="did:agent:0xabc...",
    intent="swap",
    params_digest=params_digest(params),
    created_at=utcnow_iso(),
)

# 2. The deterministic evaluator inspects the actual on-chain outcome.
observed = {"out_amount": "3501.42", "tx_hash": "0xdeadbeef...", "status": 1}
verdict = Verdict(
    evaluator_id="agentshield-evaluator-v0",
    claim_digest=keccak256(canonicalize(claim.model_dump(mode="json"))),
    output_digest=output_digest(observed),
    outcome="match",
    evaluated_at=utcnow_iso(),
)

# 3. Bind them together and sign with the evaluator's hosted key.
acct = Account.create()
envelope = Envelope.build(claim, verdict, signer=acct.address)
signature = sign(envelope, acct.key)

# 4. Anyone holding the envelope + signature can verify it.
assert verify(envelope, signature, acct.address)

See tests/ for executable examples covering every public function.

I/O contract

Layer What it does Bytes hashed
canonicalize RFC 8785 JSON Canonicalization Scheme UTF-8 bytes of canonical form
params_digest keccak-256 over canonicalized claim inputs keccak256(JCS(params))
output_digest keccak-256 over canonicalized evaluator observations keccak256(JCS(observed))
content_hash binds claim + verdict in the envelope body keccak256(JCS({schema_version, claim, verdict}))
sign / verify EIP-191 personal_sign over envelope's JCS bytes eth_sign("\x19Ethereum Signed Message:\n" + len + JCS(envelope))

The canonicalized envelope is capped at 8 KB; this is enforced by the Envelope validator. If you need to attest to a larger payload, hash it externally and put the digest in params or observed.

Why these libraries

  • jcs==0.2.1 — Anders Rundgren's reference implementation of RFC 8785. Pinned exactly: there is no other production-grade RFC 8785 implementation on PyPI, and we need byte-for-byte stability across releases. The Matrix-flavored canonicaljson package implements a different canonical form and is not compatible.
  • eth-account>=0.10,<0.14 — official Ethereum keypair / EIP-191 helpers from the eth-protocol org. We rely on Account.sign_message and Account.recover_message; both are stable across the supported range.
  • pydantic>=2.6,<3 — strict validation, frozen models, JSON-mode dumps.
  • eth-utilskeccak, to_checksum_address. Pulled in transitively by eth-account; declared explicitly to keep our import graph honest.

Out of scope for v0.1

Things this package deliberately does not do (each lives in a different repo):

  • Networking. The caller is responsible for transmitting the envelope and signature.
  • Persistence / Verdict Ledger storage. Hosted ledger writes happen in agentshield-mcp; here we only define the wire shape.
  • Key management / rotation. The hosted evaluator service holds and rotates signing keys; this library only consumes a private key passed in by the caller.
  • LangChain / framework adapters. agentshield-langchain (planned) wraps this package; no framework dependencies leak in here.
  • Higher-level orchestration. No retries, no caching, no callbacks. One envelope in, one signature out.

If you need any of the above, reach for the AgentShield hosted SDK instead.

Development

python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
ruff check .
mypy
pytest

CI runs the same gate on Python 3.10, 3.11, and 3.12 with coverage ≥90 %.

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

verdict_protocol-0.1.0.tar.gz (8.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

verdict_protocol-0.1.0-py3-none-any.whl (11.2 kB view details)

Uploaded Python 3

File details

Details for the file verdict_protocol-0.1.0.tar.gz.

File metadata

  • Download URL: verdict_protocol-0.1.0.tar.gz
  • Upload date:
  • Size: 8.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for verdict_protocol-0.1.0.tar.gz
Algorithm Hash digest
SHA256 08dd03c54c6ffa8e7108fb6353ed7147636215f9799a4425fe4a5ac65502dfdb
MD5 007cd3690f7156f5769a2011d1e2a3a2
BLAKE2b-256 47dec28f8bfb9307fc4dd4f315fc7f0f6772094b62701b2a7c507592eea388de

See more details on using hashes here.

File details

Details for the file verdict_protocol-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for verdict_protocol-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a06367aa7676e8ae3b777c9c7ea5655a1272532a487758329b65fe8dd4118a3c
MD5 8881b75e226af642730fedf4c43dde07
BLAKE2b-256 d069da5d75678c8b3b7b5f6486f7013a88d278a50bb90222cd7cd453fdbe8e72

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page