Metadata-Version: 2.4
Name: verdict-protocol
Version: 0.1.0
Summary: Schema, JCS canonicalization, and EIP-191 signing for verdict envelopes (deterministic outcome attestations).
Project-URL: Homepage, https://github.com/yeick010/verdict-protocol
Project-URL: Issues, https://github.com/yeick010/verdict-protocol/issues
Author: yeick010
License: MIT License
        
        Copyright (c) 2026 yeick010
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: agentshield,attestation,eip-191,jcs,rfc8785,verdict
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security :: Cryptography
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: eth-account<0.14,>=0.10
Requires-Dist: eth-utils<6,>=2.3
Requires-Dist: jcs==0.2.1
Requires-Dist: pydantic<3,>=2.6
Provides-Extra: dev
Requires-Dist: hypothesis>=6.100; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# verdict-protocol

[![CI](https://github.com/yeick010/verdict-protocol/actions/workflows/ci.yml/badge.svg)](https://github.com/yeick010/verdict-protocol/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)

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][positioning] for the dual-license context: this MIT package is
the wedge; the hosted evaluator and managed-key service are separate).

## Install

```bash
pip install verdict-protocol
```

## Quickstart

```python
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][rfc8785].
  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-utils`** — `keccak`, `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

```bash
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](LICENSE).

[agentshield-mcp]: https://github.com/yeick010/agentshield-mcp
[positioning]: https://github.com/yeick010/agentshield-mcp/blob/main/POSITIONING.md
[rfc8785]: https://datatracker.ietf.org/doc/html/rfc8785
