Metadata-Version: 2.4
Name: aigentsy-verify
Version: 1.5.0
Summary: Standalone offline verification for AiGentsy ProofPack v2 bundles, attestations, and policy_layer display
Project-URL: Homepage, https://aigentsy.com
Project-URL: Repository, https://gitlab.com/AiGentsy/aigentsy-ame-runtime
Project-URL: Documentation, https://aigentsy.com/data/proof_bundle_spec.md
Project-URL: Public Key, https://aigentsy-ame-runtime.onrender.com/protocol/merkle/public-key
Project-URL: Trust Center, https://aigentsy.com/trust
Author-email: AiGentsy <admin@aigentsy.com>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: aigentsy,ed25519,merkle,proof-bundle,transparency-log,verification
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
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.9
Requires-Dist: cryptography>=41.0
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == 'test'
Description-Content-Type: text/markdown

# aigentsy-verify

Standalone offline verification for AiGentsy proof bundles and attestations. **Zero dependency on AiGentsy's runtime.**

## Install

```bash
pip install aigentsy-verify
```

> **Adapter-backed replay availability.** `aigentsy-verify@1.4.0` on PyPI was built before `adapter.py` was on disk and therefore did not perform adapter-backed replay. **Fixed in `aigentsy-verify@1.5.0`** — the published 1.5.0 wheel includes `adapter.py` and the full 7-step adapter-backed replay path works from `pip install aigentsy-verify==1.5.0`. The 5-step bundle-verification path is byte-identical to 1.4.0.

## CLI

Verify a bundle offline (default — no network calls):

```bash
aigentsy-verify bundle proofpack.json
# Bundle steps run without an STH key. Adapter-backed replay is
# available from `aigentsy-verify==1.5.0` (the 1.4.0 wheel was missing
# adapter.py; fixed in 1.5.0).
```

Bundle verification with public key fetch:

```bash
aigentsy-verify bundle proofpack.json --fetch-key
# All bundle steps PASS when the bundle is well-formed.
```

JSON output for scripting:

```bash
aigentsy-verify bundle proofpack.json --json
```

Strict mode (fails if STH signature is skipped):

```bash
aigentsy-verify bundle proofpack.json --strict --fetch-key
```

Download and verify a real ProofPack:

```bash
curl -o proofpack.json https://aigentsy-ame-runtime.onrender.com/protocol/proofs/demo_deal_08effb15193a/export
aigentsy-verify bundle proofpack.json --fetch-key
```

## Python SDK — Verify in 60 Seconds

```python
from aigentsy_verify import verify_bundle, verify_attestation, fetch_public_key
import json, urllib.request

# 1. Fetch public key (cache this — it rarely changes)
public_key = fetch_public_key()

# 2. Verify a proof bundle
bundle = json.load(open("bundle.json"))
result = verify_bundle(bundle, public_key_base64=public_key)
print(result["verified"])  # True or False

# 3. Verify an attestation
resp = json.loads(urllib.request.urlopen(
    "https://aigentsy-ame-runtime.onrender.com/protocol/agents/AGENT_ID/attestation"
).read())
ok = verify_attestation(resp["attestation"], resp["signature"], public_key)
print(ok)  # True or False
```

## Verify a Proof Bundle

```python
import json
from aigentsy_verify import verify_bundle, fetch_public_key

# Load a bundle (from file, API, or any source)
with open("bundle.json") as f:
    bundle = json.load(f)

# Fetch the public key (once — cache it)
public_key = fetch_public_key()

# Verify — returns per-step results
result = verify_bundle(bundle, public_key_base64=public_key)

print(result["verified"])  # True or False
for step, detail in result["steps"].items():
    print(f"  {step}: {'PASS' if detail['passed'] else 'SKIP' if detail.get('skipped') else 'FAIL'}")
```

## Verify an Attestation

```python
import json, urllib.request
from aigentsy_verify import verify_attestation, fetch_public_key

# Fetch attestation from AiGentsy
resp = json.loads(urllib.request.urlopen(
    "https://aigentsy-ame-runtime.onrender.com/protocol/agents/AGENT_ID/attestation"
).read())

# Fetch public key
public_key = fetch_public_key()

# Verify signature
ok = verify_attestation(
    resp["attestation"],
    resp["signature"],
    public_key,
)
print(f"Attestation valid: {ok}")
```

## Sample Artifacts

The `tests/fixtures/` directory contains sample artifacts you can verify immediately:

```bash
# Clone and verify offline
python -c "
import json
from aigentsy_verify import verify_bundle, verify_attestation

bundle = json.load(open('tests/fixtures/sample_bundle.json'))
print('Bundle:', verify_bundle(bundle)['verified'])

att = json.load(open('tests/fixtures/sample_attestation.json'))
print('Attestation:', verify_attestation(att['attestation'], att['signature'], att['public_key_base64']))
"
```

Sample fixtures include a test Ed25519 key pair — they verify without network access.

## Public Key

The production Ed25519 public key is served at:

```
https://aigentsy-ame-runtime.onrender.com/protocol/merkle/public-key
```

Load it programmatically:

```python
from aigentsy_verify import fetch_public_key
key = fetch_public_key()  # returns base64-encoded Ed25519 public key
```

Or from a local file:

```python
from aigentsy_verify import load_public_key_from_file
key = load_public_key_from_file("log_public_key.json")
```

## Bundle Verification (5 steps in `verify_bundle`)

| Step | What it checks | Required? |
|------|---------------|-----------|
| 1. Bundle hash | SHA-256 of canonical JSON matches claimed hash | Yes |
| 2. Event chain | Each event's hash and prev_hash link are correct | Yes |
| 3. Merkle inclusion | RFC 6962 proof path from leaf to root | If present |
| 4. STH signature | Ed25519 signature on signed tree head | If key provided |
| 5. Cross-reference | Merkle root matches STH root hash | If both present |

(ProofPack spec_version 3.0.0 adds a sixth `actor_signatures` step that verifies per-event actor signatures; older bundles remain byte-identical at 5 steps.)

## Adapter-backed Replay (source-current, 7 checks in `verify_adapter_replay`)

When a ProofPack carries an embedded `adapter_evaluation` (Pass 66+ adapter contracts), the source verifier replays every claim it makes. Each check returns a status code; the overall `adapter_replay_status` is `ok` only if every step is `ok`.

| Step | What it checks | Status field |
|------|---------------|--------------|
| 1. Schema | Embedded `adapter_contract` declaration passes the on-disk schema | `adapter_contract_schema_status` |
| 2. Contract hash | `sha256(canonical(declaration))` matches `contract_hash` | `contract_hash_status` |
| 3. Input-schema hash | `sha256(canonical(input_schema))` matches `input_schema_hash` | `input_schema_hash_status` |
| 4. Normalized inputs | Every key in `normalized_policy_inputs` is in `allowed_policy_fields` | `normalized_policy_inputs_status` |
| 5. Validator declaration | Declared `validator_name` + `validator_version` are present and consistent with the evaluation result | `adapter_validator_status` |
| 6. Policy replay | A REJECTED event's `matched_rule` actually fires against its own evaluated inputs | `policy_replay_status` |
| 7. Overall verdict | Aggregate `ok` only if every check above is `ok` | `adapter_replay_status` |

Per-check status codes (verbatim from source):

- `ok` — check passed
- `legacy_no_adapter` — the event predates adapter contracts; no replay required
- `schema_fail` — adapter contract declaration failed schema validation
- `contract_hash_mismatch` — recomputed contract hash does not match claimed value
- `input_schema_hash_mismatch` — recomputed input-schema hash does not match claimed value
- `normalized_inputs_not_in_allowed_policy_fields` — claim referenced a field not declared by the contract
- `validator_declaration_missing` — required validator metadata absent
- `validator_result_inconsistent` — validator result contradicts the declared validator
- `matched_rule_does_not_fire_against_evaluated_inputs` — the rule the runtime claims matched does not fire on replay
- `adapter_evaluation_shape_invalid` — top-level shape of `adapter_evaluation` is malformed

The 7-step adapter-backed replay path is available from the published wheel **starting with `aigentsy-verify==1.5.0`**. The 1.4.0 wheel was missing `adapter.py`; that gap is closed in 1.5.0 (see install note at the top).

## API

### `verify_bundle(bundle, public_key_base64="", sth=None) -> dict`
Complete 5-step verification. Returns `{"verified": bool, "steps": {...}}`.

### `verify_attestation(attestation, signature_base64, public_key_base64) -> bool`
Verify an Ed25519-signed outcome attestation.

### `verify_inclusion(leaf_hash, leaf_index, tree_size, proof, expected_root) -> bool`
Verify an RFC 6962 Merkle inclusion proof.

### `verify_sth_signature(sth, public_key_base64) -> bool`
Verify a signed tree head signature.

### `verify_consistency(old_size, new_size, old_root, new_root, proof) -> bool`
Verify an RFC 6962 Merkle consistency proof (append-only guarantee).

### `verify_anchor_receipt(receipt) -> tuple[bool, dict]`
Verify an STH anchor receipt's digest integrity. Returns `(passed, details)`.

### `fetch_public_key(url=...) -> str`
Fetch the Ed25519 public key from AiGentsy's runtime.

### `load_public_key_from_file(path) -> str`
Load the public key from a local JSON file.

### `compute_bundle_hash(deal_id, proofs, events, merkle_inclusion) -> str`
Compute the SHA-256 bundle hash.

### `verify_event_chain(events) -> dict`
Verify event hash integrity and prev_hash chain linkage.

### `verify_adapter_replay(bundle) -> dict`
Adapter-backed replay over an embedded `adapter_evaluation`. Returns the seven per-check status fields plus the overall `adapter_replay_status`. Available in the published wheel from `aigentsy-verify==1.5.0` (the 1.4.0 wheel did not include `adapter.py`).

## Resources

- [Proof Bundle Spec](https://aigentsy.com/data/proof_bundle_spec.md)
- [Conformance Vectors](https://aigentsy.com/data/conformance_vectors.json)
- [Public Key (runtime)](https://aigentsy-ame-runtime.onrender.com/protocol/merkle/public-key)
- [Trust Center](https://aigentsy.com/trust)
- [Verify Page](https://aigentsy.com/verify)

## License

MIT — see [LICENSE](LICENSE).
