No project description provided
Project description
Axiomatic ProofKit (Python) is the client SDK for building and publishing p1 Proof-of-Valuation (PoVal) attestations on Algorand.
The goal is a simple, trust-minimized flow:
- Build a canonical p1 payload (JCS/ACJ-style JSON).
- Publish it on-chain as the note of a 0-ALGO self-transaction.
- Keep signing and key management on the client side.
- Allow anyone to independently recompute and verify what was published.
This SDK does not depend on any Axiomatic backend.
Who is this for?
Use axiomatic_proofkit if you:
- Build Python back-ends that need to issue PoVal attestations on Algorand.
- Integrate model-based valuations into RWA / tokenization / lending flows.
- Want deterministic, auditable
p1payloads aligned with the Node SDKs.
If you only need to verify on-chain notes, see axiomatic_verifier.
Typical use cases
-
Real estate tokenization
- Compute a fair value
vand intervalufor a property. - Build a
p1attestation withaxiomatic_proofkit. - Anchor the PoVal proof on Algorand TestNet/MainNet as a 0-ALGO self-tx.
- Compute a fair value
-
On-chain collateral / lending
- Issue PoVal attestations for assets posted as collateral.
- Use the on-chain note + txid as input for your credit/risk policies.
-
Back-office & audit tooling
- Periodically issue updated valuations.
- Keep a verifiable trail of model versions, hashes and timestamps.
Installation
Requires Python 3.10+.
pip install axiomatic_proofkit
pip install py-algorand-sdk
Exposed API
From axiomatic_proofkit:
build_p1(...)canonical_note_bytes_p1(p1)assert_note_size_ok(p1, max_bytes=...)build_canonical_input(raw_input, allowed_keys=...)compute_input_hash(canonical_input, allowed_keys=...)publish_p1(p1, from_addr=..., sign=..., network=..., algod=..., wait_rounds=...)PublishError
These are the only functions you need for typical integrations.
p1 structure
build_p1 returns a dict of the form:
p1 = {
"s": "p1", # schema marker
"a": "re:EUR", # asset tag (e.g. "re:EUR")
"mv": "v2", # model version
"mh": "", # model hash (hex, optional)
"ih": "...", # input hash (hex, required)
"v": 550000.0, # point estimate (e.g. value)
"u": [520000.0, 580000.0], # uncertainty range [low, high]
"ts": 1762609210, # unix epoch seconds
}
The object is normalized and serialized using a JCS/ACJ-style canonical JSON encoder for stable hashing and cross-language parity.
Quickstart: publish a p1 to Algorand TestNet
The following example mirrors the internal smoke test used to validate the SDK.
1. Environment
Create a .env file next to your script:
ALGORAND_MNEMONIC=your 25-word mnemonic for a TestNet account
ALGORAND_NETWORK=testnet
# Optional: override default node
# ALGOD_URL=https://testnet-api.algonode.cloud
For production, use a secure signing setup (wallet, KMS, HSM, etc.). This example uses a mnemonic only for demonstration.
2. Example script (publish_p1_example.py)
import os
import sys
import json
import base64
from pathlib import Path
from algosdk import account, mnemonic, encoding, transaction
from algosdk.v2client.algod import AlgodClient
from axiomatic_proofkit import (
build_p1,
canonical_note_bytes_p1,
assert_note_size_ok,
build_canonical_input,
compute_input_hash,
publish_p1,
)
ROOT = Path(__file__).resolve().parent
def load_env_from_file(env_path: Path) -> None:
try:
for line in env_path.read_text(encoding="utf-8").splitlines():
if not line or line.strip().startswith("#") or "=" not in line:
continue
k, v = line.split("=", 1)
k, v = k.strip(), v.strip()
if k and (k not in os.environ):
os.environ[k] = v
except FileNotFoundError:
pass
load_env_from_file(ROOT / ".env")
MNEMONIC = os.getenv("ALGORAND_MNEMONIC")
NETWORK = (os.getenv("ALGORAND_NETWORK") or "testnet").strip()
ALGOD_URL = (
os.getenv("ALGOD_URL")
or (
"https://mainnet-api.algonode.cloud"
if NETWORK == "mainnet"
else "https://testnet-api.algonode.cloud"
)
).strip()
if not MNEMONIC:
print("❌ ALGORAND_MNEMONIC missing.", file=sys.stderr)
sys.exit(1)
def compute_input_hash_from_golden() -> str:
"""
If golden/p1_input.json exists, compute its canonical ACJ/JCS hash.
Otherwise return a deterministic placeholder for the smoke test.
"""
golden_dir = ROOT / "golden"
inp_path = golden_dir / "p1_input.json"
if not inp_path.is_file():
return "0" * 64
try:
raw = json.loads(inp_path.read_text(encoding="utf-8"))
except Exception as e:
print(f"⚠️ Unable to read golden/p1_input.json: {e}")
return "0" * 64
allowed_keys = list(raw.keys())
cin = build_canonical_input(raw, allowed_keys=allowed_keys)
ih = compute_input_hash(cin, allowed_keys=allowed_keys)
print(f"✅ Golden input hash: {ih}")
return ih
def main() -> None:
# 1) Derive private key and address from mnemonic (demo only)
sk = mnemonic.to_private_key(MNEMONIC)
addr = account.address_from_private_key(sk)
# 2) Compute input hash (from golden file if available)
ih = compute_input_hash_from_golden()
# 3) Build canonical p1
p1 = build_p1(
asset_tag="re:EUR",
model_version="v2",
model_hash_hex="",
input_hash_hex=ih,
value_eur=550_000,
uncertainty_low_eur=520_000,
uncertainty_high_eur=580_000,
timestamp_epoch=None, # use "now"
)
# 4) Inspect note size and hash
note_bytes, note_sha, note_len = canonical_note_bytes_p1(p1)
assert note_bytes is not None # just to show it's a bytes-like object
assert_note_size_ok(p1)
print(f"P1 note size: {note_len} bytes | sha256: {note_sha}")
# 5) Client-side signer: keep your keys local
def sign(unsigned_bytes: bytes) -> bytes:
"""
unsigned_bytes: msgpack-encoded UnsignedTransaction.
Return: msgpack bytes of the SignedTransaction.
"""
tx_dict = encoding.msgpack.unpackb(unsigned_bytes)
txn = transaction.Transaction.undictify(tx_dict)
stx = txn.sign(sk)
stx_b64 = encoding.msgpack_encode(stx) # base64(msgpack signed)
return base64.b64decode(stx_b64) # raw msgpack bytes
# 6) Algod client (Algonode by default)
algod = AlgodClient("", ALGOD_URL)
# 7) Publish p1 as a 0-ALGO self-transaction note
res = publish_p1(
p1,
network=NETWORK,
algod=algod,
from_addr=addr,
sign=sign,
wait_rounds=4,
)
print("PUBLISHED:")
print(json.dumps(res, indent=2))
if __name__ == "__main__":
main()
Run:
python publish_p1_example.py
You should see a JSON result with:
txidexplorer_urlnote_sha256note_sizenetwork
You can open the explorer URL and inspect the on-chain note.
Publish → verify (end-to-end)
To verify a published p1 attestation from Python, use axiomatic_verifier:
from axiomatic_verifier import verify_tx
res = verify_tx(
txid="YOUR_TXID",
network="testnet",
# or your own indexer:
# indexer_url="https://testnet-idx.algonode.cloud",
max_skew_past_sec=3600,
max_skew_future_sec=300,
)
print(res["verified"], res.get("reason"))
This checks:
- that the note is structurally valid,
- that canonicalization and
sha256match, - and that the timestamp
tsis within your allowed time window.
Security notes
-
The
signfunction is fully controlled by you. -
For real integrations, replace inline mnemonic signing with:
- wallet connectors,
- custodial services,
- HSM/KMS or cloud KMS.
-
The SDK never sends your secrets anywhere and does not rely on Axiomatic servers.
This is an early-access SDK: feedback and issues are very welcome.
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 axiomatic_proofkit-0.1.4.tar.gz.
File metadata
- Download URL: axiomatic_proofkit-0.1.4.tar.gz
- Upload date:
- Size: 7.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e33c48a552c7796552fee7cb9f550efa89c4fb6ad7ec24ba9b6be3378a9a52dd
|
|
| MD5 |
d840de04f847ea5dde61967339faad14
|
|
| BLAKE2b-256 |
a667b1a62bf00f37cfb0a16a7a482aca3054dd3c7938d690e7e7628d567e9762
|
File details
Details for the file axiomatic_proofkit-0.1.4-py3-none-any.whl.
File metadata
- Download URL: axiomatic_proofkit-0.1.4-py3-none-any.whl
- Upload date:
- Size: 8.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
919f1cc149dafa0f2a609e2719ca0f400f1b2d19f47119eda4cd978236e20275
|
|
| MD5 |
a69fce89de483685b7d93e48aed0d889
|
|
| BLAKE2b-256 |
4f21c345cefa1527f1bb0fc01d06016f979d7728f70cf11188df477db3c43f68
|