Standalone offline verification for AiGentsy ProofPack v2 bundles, attestations, and policy_layer display
Project description
aigentsy-verify
Standalone offline verification for AiGentsy proof bundles and attestations. Zero dependency on AiGentsy's runtime.
Install
pip install aigentsy-verify
Adapter-backed replay availability.
aigentsy-verify@1.4.0on PyPI was built beforeadapter.pywas on disk and therefore did not perform adapter-backed replay. Fixed inaigentsy-verify@1.5.0— the published 1.5.0 wheel includesadapter.pyand the full 7-step adapter-backed replay path works frompip 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):
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:
aigentsy-verify bundle proofpack.json --fetch-key
# All bundle steps PASS when the bundle is well-formed.
JSON output for scripting:
aigentsy-verify bundle proofpack.json --json
Strict mode (fails if STH signature is skipped):
aigentsy-verify bundle proofpack.json --strict --fetch-key
Download and verify a real ProofPack:
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
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
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
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:
# 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:
from aigentsy_verify import fetch_public_key
key = fetch_public_key() # returns base64-encoded Ed25519 public key
Or from a local file:
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 passedlegacy_no_adapter— the event predates adapter contracts; no replay requiredschema_fail— adapter contract declaration failed schema validationcontract_hash_mismatch— recomputed contract hash does not match claimed valueinput_schema_hash_mismatch— recomputed input-schema hash does not match claimed valuenormalized_inputs_not_in_allowed_policy_fields— claim referenced a field not declared by the contractvalidator_declaration_missing— required validator metadata absentvalidator_result_inconsistent— validator result contradicts the declared validatormatched_rule_does_not_fire_against_evaluated_inputs— the rule the runtime claims matched does not fire on replayadapter_evaluation_shape_invalid— top-level shape ofadapter_evaluationis 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
License
MIT — see LICENSE.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aigentsy_verify-1.5.0.tar.gz.
File metadata
- Download URL: aigentsy_verify-1.5.0.tar.gz
- Upload date:
- Size: 56.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1188d5ac6e3ccb25e3679b74bd0c83e5a73a627548517db53f603d31a92cc55f
|
|
| MD5 |
9b79baa10ee22bb9d4b1e44a14f9357a
|
|
| BLAKE2b-256 |
8e62867d13cd5255b08c8b14e47b32e47ca66e8290e2fbd94f2b0386539309c7
|
File details
Details for the file aigentsy_verify-1.5.0-py3-none-any.whl.
File metadata
- Download URL: aigentsy_verify-1.5.0-py3-none-any.whl
- Upload date:
- Size: 33.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a57e2108bb78520190ea8c0971f0177f431dec11371cb96c0dda4cb8f8e87f5
|
|
| MD5 |
04ea7c126ae49d1b94cda0b26da91a9e
|
|
| BLAKE2b-256 |
f134bcd37f6a47544ee03af6a0f4ff7027609e51b2447fac0ad871e25dc854b6
|