AICEPAICEP AICEP 0.1 — Public Draft (RFC)
AICEP is an experimental public draft, provided “as is” and without warranty. Use it at your own risk. We test it extensively, but testing is not a guarantee. Full disclaimer

← AICEP home · Runbook index

AICEP Phase-2 reference scripts (proposed extension, NOT 0.1 normative)

Follows encryption-scheme.md v2. Local reference only; nothing deployed.

Files: aicep_pub.py (publisher), aicep_sub.py (verify + ingest), aicep_common.py, tests/test_tamper.py. Crypto: age X25519 via pyrage (in memory), Ed25519 via cryptography. No hand-rolled crypto.

Deviation from v2 text: the signature is a raw detached Ed25519 sig (base64) in manifest.json.sig, not minisign .minisig format. Same algorithm and same signed bytes; v2 should name either format.

Setup

cd reference
python3 -m venv .venv && .venv/bin/pip install cryptography pyrage pytest

Keys (throwaway, paths only; never paste key values into prompts/logs)

.venv/bin/python -c "import os; from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey as K; from cryptography.hazmat.primitives import serialization as s; open('/dev/shm/sign.pem','wb').write(K.generate().private_bytes(s.Encoding.PEM,s.PrivateFormat.PKCS8,s.BestAvailableEncryption(os.environ['AICEP_SIGN_KEY_PASSPHRASE'].encode())))"
.venv/bin/python -c "import pyrage; i=pyrage.x25519.Identity.generate(); open('/dev/shm/id.txt','w').write(str(i)+'\n'); print(i.to_public())"   # prints PUBLIC recipient only
chmod 600 /dev/shm/sign.pem /dev/shm/id.txt

Registry (registry.json, human-maintained; ingest refuses unless state=verified and verified_by/at set):

{"ed25519:<16hex>": {"sender_id":"swarmA","ed25519_pub":"<b64 raw 32B>","state":"verified",
  "verified_by":"<human>","verified_at":<unix>,"expires":<unix ≤90d>,"revoked_at":null}}

key id = ed25519: + first 16 hex of sha256(raw public key).

Publish

export AICEP_SIGN_KEY_FILE=/dev/shm/sign.pem
# passphrase: AICEP_SIGN_KEY_PASSPHRASE (from your secret manager) or OS keyring service 'aicep', user 'AICEP_SIGN_KEY_FILE'.
# Unencrypted PEM keys are refused. --in must be on tmpfs (/dev/shm); other paths are refused.
.venv/bin/python aicep_pub.py --in objects.json --out ./pub --compartment c1 \
   --sender-id swarmA --recipient age1... --state pub_state.json --ttl 3600

objects.json = list of DLP-cleared {name,type,classification,body,supersedes?}. Output: pub/c1/<batch_uuid>/{<uuid>.age..., meta.age, manifest.json, manifest.json.sig}; padded to power-of-2 buckets (min 4 KiB).

Ingest

export AICEP_AGE_IDENTITY_FILE=/dev/shm/id.txt
.venv/bin/python aicep_sub.py ./pub/c1/<batch_uuid> --compartment c1 --registry registry.json --state sub_state.json

Exit 0 + JSON {"untrusted": true, "status": "accepted", ...}; exit 2 + {"status":"rejected","reason":...}. Order: registry → signature → v/alg → expiry → seq>last_seq (gap_alarm) → recipient/compartment → folder == manifest → sha256 all → decrypt in memory → envelope batch_id/file_id/seq/size → meta match → persist last_seq.

Tests (see v2.3 section for current counts)

.venv/bin/python -m pytest -q tests

v2.2 gate

python3 aicep_ingest.py <batch_dir> --config gate.json --compartment c1 --registry registry.json --state sub_state.json

Needs AICEP_AGE_IDENTITY_FILE and AICEP_VERIFIER_KEY_FILE (a separate verifier key, mode 600). gate.json = {"verifier_pub","pinned_script_sha256"}. Exit 0 = gate pass; exit 4 = fail, with no content.

v2.3 delivery guarantees (proposed Phase 2 extension)

aicep_transport.py: TransportAdapter abstract class plus LocalFolderAdapter, which uses _staging/, a READY marker written last, pub/, processing/ with leases, holding/, done/, and dlq/ with a signed reason. aicep_pub.Outbox: reserves seq and logs it as staged before publish, retries at 1/4/12 h then raises an unconfirmed alert, and accepts cumulative signed receipts. aicep_sub.Receiver: state machine fetched → verified → committing → committed, with crash recovery. Also: idempotent redelivery, equivocation alarm, reorder holding with a 30 min window and then a human hold, a prev_batch_id chain, a dlq (3 transient tries / 1 crypto, signed reason, human-only redrive), a hash-chained ledger, and a QoP floor (sign+encrypt only). Tests: 188 automated tests, all passing (v2.5.1). test_tamper.py has 29 (27 defs), test_attestation.py has 10, test_delivery.py has 22 (21 defs, one parametrized ×2).

v2.5 outside-review fixes