Skip to main content

ARC privacy framework: PQ-encrypted, attested, validator-anchored data layer for any application.

Project description

arc-avs-sdk

Python SDK for the ARC Privacy AVS — a Sepolia-anchored validator network that proves applications process user data without retention. Same wire format as @arc-avs/sdk on npm; envelopes round-trip byte-exact between TS and Python.

Two custody modes:

  • key_custody="server" (default) — runtime generates and holds each user's KEM keypair. Backend can decrypt records on demand. Convenient for tests and managed-account flows.
  • key_custody="client" — non-custodial. The user's KEM secret stays on the client (typically derived from a wallet PRF). The backend accepts pre-sealed envelopes via persist_envelope and serves them back as ciphertext via fetch_envelope. read / process / export_user raise ClientCustodyError because they need the secret the server doesn't have.
pip install arc-avs-sdk
# adapters & router are optional extras
pip install "arc-avs-sdk[postgres,neo4j,chain]"

Quick start

import asyncio
from arc_avs_sdk import arc, init
from arc_avs_sdk.adapter.memory import MemoryAdapter

schema = arc.schema(
    app_id     = "your-app.com",
    compliance = ["GDPR", "CCPA"],
    classes    = {
        "User": arc.identity({
            "profile": arc.encrypted.struct({
                "name":  arc.encrypted.string(),
                "email": arc.encrypted.email(),
            }),
            "events": arc.collection(
                item_kind="event",
                query="indexed",
                index_fields=["kind"],
                retention="permanent",
            ),
        }),
    },
)

async def main() -> None:
    runtime = await init(schema, adapter=MemoryAdapter())
    user, _ = await runtime.create_user("User", {"name": "Alice", "email": "a@b.c"})
    ref, proof = await runtime.put_record(
        user, "User", "event", {"kind": "login"}, index_fields={"kind": "login"}
    )
    print(proof.input_hash)

asyncio.run(main())

Non-custodial (key_custody="client")

The user's KEM secret never reaches the backend. Frontend (browser, mobile, any TS/JS runtime) seals envelopes locally and ships bytes to the Python backend; the backend persists, commits the proof to the validator network, and serves envelopes back as ciphertext on read. Decryption only happens client-side.

Backend (Python):

from arc_avs_sdk import arc, init, encode_envelope, UserHandle
from arc_avs_sdk.adapter.postgres import PostgresAdapter

runtime = await init(schema, adapter=PostgresAdapter(...), key_custody="client")

# 1. Register the client-derived identity. The user_kem_public_key arrives
#    from the frontend (e.g. derived from a wallet PRF).
user = runtime.register_user("ar_alice", user_kem_public_key=client_pubkey_bytes)

# 2. Persist a pre-sealed envelope. The frontend already sealed it with
#    @arc-avs/sdk's sealEnvelope; the backend just stores + commits the proof.
ref, proof = await runtime.persist_envelope(
    user, "User", "event", envelope_from_client,
    index_fields={"kind": b"\\x01..."},   # detEnc bytes from client
)

# 3. Serve envelopes back as ciphertext. encode_envelope produces the
#    cross-language wire format the TS SDK can decode.
envelope = await runtime.fetch_envelope(user, ref)
return Response(content=encode_envelope(envelope), media_type="application/octet-stream")

# These raise ClientCustodyError — the server doesn't have the secret key:
#   await runtime.create_user(...)
#   await runtime.put_record(...)
#   await runtime.read(...)
#   await runtime.process(...)
#   await runtime.export_user(...)

Frontend (TypeScript, @arc-avs/sdk):

import { sealEnvelope, openEnvelope } from "@arc-avs/sdk";

// Seal locally — backend never sees plaintext
const env = sealEnvelope({
  plaintext: new TextEncoder().encode(JSON.stringify({ kind: "login" })),
  userKemPublicKey: clientKp.publicKey,
  appEcdsaPrivateKey, appMlDsaPrivateKey,
  appId, className: "User.event", nonceSeq: 1n,
});

// Ship envelope bytes to backend's persist endpoint
await fetch("/api/arc/persist", { method: "POST", body: encodeEnvelope(env) });

// On read, backend returns ciphertext bytes — decrypt locally
const buf  = await (await fetch(`/api/arc/envelope/${ref}`)).arrayBuffer();
const env2 = decodeEnvelope(new Uint8Array(buf));
const plaintext = openEnvelope({ envelope: env2, userKemSecretKey: clientKp.secretKey });

purge_user works in either custody mode — it crypto-shreds the wrapped keys at the adapter level, no plaintext access required. That covers GDPR Art. 17 even when the runtime never had the secret to begin with.

What's shipped

  • Crypto layer — ML-KEM-768, ML-DSA-65, AES-256-GCM, secp256k1 ECDSA, keccak256
  • Schema DSL — domain-agnostic, byte-canonical, on-chain hash matches the TS canonicalization
  • Runtime · server-custodycreate_user, put_record, read, list, process, purge_user, export_user
  • Runtime · client-custody (non-custodial)register_user, persist_envelope, fetch_envelope, list, purge_user
  • Adaptersmemory, postgres, mongo, redis, neo4j (graph-RAG / agent memory)
  • Processorsopenai, anthropic, mistral, kimi, nous
  • Validator routerweb3.py based EIP-712 attestation submission

Compatibility

The Python CipherEnvelope serializes to the same byte layout as the TypeScript SDK. A round-trip test in tests/test_envelope_compat.py proves that an envelope sealed in TS opens in Python and vice-versa.

Property TS Python
Schema canonical hash keccak256(canonicalize_schema(s)) keccak256(canonicalize_schema(s))
bind_aad(app_id, class, seq) byte-identical byte-identical
bind_digest(...) byte-identical byte-identical
proof_bind_digest(...) byte-identical byte-identical

This matters because the on-chain inputHash recorded by PrivacyTaskManager must agree across language stacks.

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

arc_avs_sdk-1.0.0a6.tar.gz (41.5 kB view details)

Uploaded Source

Built Distribution

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

arc_avs_sdk-1.0.0a6-py3-none-any.whl (51.4 kB view details)

Uploaded Python 3

File details

Details for the file arc_avs_sdk-1.0.0a6.tar.gz.

File metadata

  • Download URL: arc_avs_sdk-1.0.0a6.tar.gz
  • Upload date:
  • Size: 41.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for arc_avs_sdk-1.0.0a6.tar.gz
Algorithm Hash digest
SHA256 b8245de1a20cae9f3b992dc79b60a6e930c5fc213fd046e1b4ff34d0bd84d0af
MD5 74c4bffa939ef26ccbd60ab09cfb7b55
BLAKE2b-256 76b8869b78c0a982bfaaed60e3e576fa05eeb4b96edc9a1467fc2cd020dcc085

See more details on using hashes here.

File details

Details for the file arc_avs_sdk-1.0.0a6-py3-none-any.whl.

File metadata

  • Download URL: arc_avs_sdk-1.0.0a6-py3-none-any.whl
  • Upload date:
  • Size: 51.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for arc_avs_sdk-1.0.0a6-py3-none-any.whl
Algorithm Hash digest
SHA256 a4d11850d067afd4228baa3390a8ada54907446c2f4798cf0e9bb14c9fbd1d55
MD5 f5c3f727950a49b9337b0330688de3b6
BLAKE2b-256 865642f2ffc5ce5e4c0c0623fda5b71def4d47b4d7b887ff2c4194560f26db52

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