Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ CONVERGENCE*.md
*.privat.md
.geminirules
.claude/

# interop example deps (npm) and project-local venvs
node_modules/
.venv314/
43 changes: 43 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,49 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.5.0] - 2026-08-17

### Added
- **BRC-138 — Single-Use Signed Proofs** (`bsv_brc.brc138`), the first Python
implementation of the standard, byte-compatible with the reference
TypeScript `@bsv/auth`:
- `create_auth_proof` / `verify_auth_proof` over the spec's canonical
encoding (newline-delimited auth fields; request payloads bound in via a
VarInt length prefix), BRC-42/43 child-key derivation per proof
(`protocolID [2, name]`, `keyID = nonce`, `counterparty = verifier`),
SHA-256 + DER ECDSA signing (matches `@bsv/sdk` `createSignature`).
- `check_auth_proof_data` — pure shape/action/freshness checks (mirrors
`checkAuthSigData`), clock-skew tolerance, expiry-bound.
- `AuthProof` / `AuthProofData` with the spec's wire form
(`signature` as an array of byte values; hex accepted on input for
wallet interop).
- Single-use stores: `SingleUseStore` ABC + `MemorySingleUseStore`
(locked, lazy eviction) + `SqliteSingleUseStore` (atomic
`INSERT OR IGNORE` against a unique index; bounded retention).
- `AuthProofMiddleware` — optional Starlette/ASGI auth gate
(proof via `x-bsv-auth-proof` header or JSON body `proof` member;
401 otherwise; sets `scope["bsv_auth_proof"]`).
- `crypto.keys.derive_signing_public_key` — the verifier-side counterpart
of BRC-43 signing-key derivation.
- **Cross-implementation proof**: `examples/brc138_interop/` runs a
live 4-way interop check against `@bsv/auth`+`@bsv/sdk` (Python↔Node,
bodyless and body-bound), and `tests/test_brc138_interop.py` pins the
certified vectors as a Node-free regression test.
- `docs/MODERNIZATION.md` — full gap analysis of `bsv-brc` vs the current
BRC ecosystem (spec set current to 2026-08-12): the payments 402 family
(BRC-118 multipart, BRC-120 x402, BRC-121 simple 402), BEEF V2
(BRC-96/158), overlay sync (BRC-76 GASP, BRC-136 BASM), identity-adjacent
standards, and the corrected BRC-101/108/116 notes.

### Fixed / corrected
- README/CHANGELOG claims about "out of scope" BRCs were stale and wrong:
BRC-101 is *SHIP/SLAP facilitator URL protocols* (not "aspirational"),
BRC-108 is the *Identity-Linked Token Protocol* (not Mandala-bound),
BRC-116 is *Wallet Permissions and Counterparty Trust* (no sCrypt
toolchain involved). Replaced with a current out-of-scope note.
- The venv note in `CLAUDE.md` is updated: the suite is verified on
Python 3.14 + `bsv-sdk` 2.3.3 (197 pre-existing tests stay green).

## [0.4.0] - 2026-06-03

### Added
Expand Down
41 changes: 36 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ open (it ships only the overlay *client* side).
| `bsv_brc.brc094` | [BRC-94](https://bsv.brc.dev/key-derivation/0094) | Verifiable ECDH shared secrets via Schnorr proof |
| `bsv_brc.brc104` | [BRC-103/104](https://bsv.brc.dev/peer-to-peer/0104) | ASGI mutual-auth adapter over `bsv.auth` |
| `bsv_brc.brc105` | [BRC-105](https://bsv.brc.dev/payments/0105) | HTTP 402 micropayment middleware + client |
| `bsv_brc.brc138` | [BRC-138](https://bsv.brc.dev/peer-to-peer/0138) | Single-use signed proofs — login in one request (`@bsv/auth`-compatible) |
| `bsv_brc.brc22` | [BRC-22](https://bsv.brc.dev/overlays/0022) | **Server-side** overlay topic submission (`/submit`) |
| `bsv_brc.brc24` | [BRC-24](https://bsv.brc.dev/overlays/0024) | **Server-side** lookup services — the feed (`/lookup`) |
| `bsv_brc.brc87` | [BRC-87](https://bsv.brc.dev/overlays/0087) | `tm_`/`ls_` overlay name validation |
Expand Down Expand Up @@ -115,6 +116,30 @@ ok = overlay.verify_state("tm_posts", outpoints) # local state_root == node'
Async apps can use the pure `build_submit_headers` / `parse_steak` /
`parse_lookup_answer` / `parse_state` helpers with their own HTTP client.

### BRC-138: Authenticate a request in one shot (login, no handshake)

Single-use signed proofs: prove you hold an identity key in one request,
without a BRC-103 session. Interoperates with the reference TypeScript
`@bsv/auth` out of the box (same default protocol `[2, "bsv auth proof"]`):

```python
from bsv_brc.brc138 import MemorySingleUseStore, create_auth_proof, verify_auth_proof

# Client (e.g. a browser wallet): sign a "login" proof toward the server key
proof = create_auth_proof(client_identity_privkey, server_identity_pubkey, "login")
# ...transmit proof.to_dict() (signature = byte values, per spec)...

# Server: shape -> action -> freshness -> signature -> single-use, atomically
identity = verify_auth_proof(
server_identity_privkey, proof, "login",
single_use_store=MemorySingleUseStore(), # SqliteSingleUseStore for persistence
)
# identity == client public key -> caller provably holds the key
```

See [`examples/brc138_auth.py`](examples/brc138_auth.py), and
`examples/brc138_interop/` for the Python ⇄ TypeScript byte-compat proof.

### BRC-105: Accept micropayments on any endpoint

```python
Expand Down Expand Up @@ -166,6 +191,7 @@ cert = issue(
## Roadmap

- [x] BRC-103/104 — Mutual authentication (ASGI adapter over `bsv.auth`)
- [x] BRC-138 — Single-use signed proofs (login in one request, `@bsv/auth`-compatible)
- [x] BRC-22 — Server-side overlay topic submission (`/submit`)
- [x] BRC-24 + `OverlayEngine` — Lookup services + a runnable overlay node
- [ ] BRC-35 — Global KVStore over overlay (pending byte-exact interop check)
Expand All @@ -174,12 +200,16 @@ cert = issue(
- [x] Per-topic state root + `GET /state` endpoint — **matches `overlay.peck.to` `/state`**
- [x] Overlay `OverlayClient` (submit / lookup / state / verify) — defaults to `overlay.peck.to`
- [x] Optional SPV verify on submit (`OverlayEngine(verify_tx=...)`, injectable ChainTracker)
- [ ] BRC-118 multipart transport + BRC-121 simple-402 profile for `brc105`
- [ ] paymail (→ bsv-compat), peck-anchor client + headers.peck.to ChainTracker (peck-infra lib)
- [ ] GASP-style peer sync + on-chain root anchoring
- [ ] BRC-76 GASP peer sync / BRC-136 BASM + on-chain root anchoring

Deliberately **out of scope** (see `CHANGELOG.md`): BRC-101 (aspirational,
no normative behavior), BRC-108 (no Mandala/BRC-92/107 token base),
BRC-116 (needs an external sCrypt toolchain).
See [`docs/MODERNIZATION.md`](docs/MODERNIZATION.md) for the full BRC
ecosystem gap analysis (payments 402 family, BEEF v2, overlay sync).

Out of scope today: SHIP/SLAP (BRC-88) — the overlay.social model is
GASP/Merkle-roots, not SHIP/SLAP; BRC-120 x402 conformance (frozen external
spec) and the 1Sat token series (BRC-147/150/159/160) — separate concerns.

## Development

Expand All @@ -188,7 +218,8 @@ git clone https://github.com/datamynt/bsv-brc-python.git
cd bsv-brc-python
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[starlette,dev]"
pytest -v # 197 tests
pytest -v # 235 tests
```
```

## License
Expand Down
147 changes: 147 additions & 0 deletions docs/MODERNIZATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# bsv-brc-python — BRC ecosystem modernization review

_Sist oppdatert: 2026-08-17 · Agent: dsh-peck/deepseek-v4-flash_

This document maps `bsv-brc` against the **current** BRC standards
repository (`bsv-blockchain/BRCs`, spec set current to 2026-08-12, 150+
standards up to BRC-228) and lays out what modernization means for this
library. It is the basis for the 0.5.0 release; items below are prioritized.

## 1. Where the library stands (verified)

Baseline on this round: the full suite (**197 tests**) passes on
Python 3.14 with the latest `bsv-sdk` **2.3.3** (the pin floor was 2.1.3).
It remains the only OSS Python package providing the *server side* of the
BSV stack: BRC-22/24 overlay node, BRC-103/104 auth adapter, BRC-105 402
payments, BRC-52 certificates, BRC-94 Schnorr proofs, BRC-87 names.
Consumers in the wild (this monorepo): `peck-certifier` (brc052),
`peck-web` (brc104 AuthMiddleware + brc052/crypto), `bsv-compat` (bitcom).

## 2. What matured/changed in the BRC ecosystem since 0.4.0 (2026-06)

### 2.1 Removed / corrected misconceptions in this repo's docs

The "out of scope" claims in `README.md`/`CHANGELOG.md` are **stale and
factually wrong** against the current BRC index:

| Claim in repo | Reality (2026-08 BRC index) |
|---|---|
| "BRC-101: aspirational, no normative behavior" | BRC-101 = *Diverse Facilitators and URL Protocols for SHIP and SLAP Overlay Advertisements* (overlays/0101.md) — has content. |
| "BRC-108: no Mandala/BRC-92/107 token base" | BRC-108 = *Identity-Linked Token Protocol* (tokens/0108.md) — links token state to the identity ledger of BRC-42/52/53. |
| "BRC-116: needs an external sCrypt toolchain" | BRC-116 = *Wallet Permissions and Counterparty Trust* (wallet/0116.md) — pure wallet/wire concept, nothing sCrypt. |
| "BRC-88: not pursued" | Still correct — SHIP/SLAP remains out of the overlay.social model (GASP + state roots instead). |

These have been corrected in this release (see `README.md`, `CLAUDE.md`).

### 2.2 New standards directly relevant to this library

**Payments — the 402 family matured (payments/README.md):**
- **BRC-105** remains the *primary* BSV-native HTTP monetization framework.
- **BRC-118** — Multipart body transport for BRC-105 (large chained BEEFs
blow past header limits; 8 KB auto-switch; backward-compatible, header
transport not deprecated). Direct extension of our `brc105` module.
- **BRC-120** — x402 (frozen external spec, stateless settlement-gated).
- **BRC-121** — Simple 402 (small BSV-specific profile; `x-bsv-sats`,
`x-bsv-server`, `x-bsv-beef`, `x-bsv-nonce`, `x-bsv-time`, `x-bsv-vout`;
replay via wallet `isMerge`). Reference impls: `@bsv/402-pay`,
`go-402-pay`, browser extension.
- **BRC-125** — PeerPay URI scheme for BRC-29 payments.
- **BRC-228** — Unlinkable payments under the identity paradigm (sender
side profile of BRC-29, ephemeral per-payment keys).

**Authentication — request auth beyond BRC-103:**
- **BRC-138** — Single-Use Signed Proofs for Request Authentication: a
one-shot, expiry-bound, action-bound signed proof; login and one-shot
actions without a full BRC-103 session. Reference impl `@bsv/auth`
(TS). **→ implemented in this release as `bsv_brc.brc138`, proven
byte-compatible with `@bsv/auth` in both directions.**

**Transactions — BEEF family:**
- **BRC-96** — BEEF V2 Txid-only extension (bandwidth win for ancestors).
- **BRC-158** — Outpoint BEEF.
- **BRC-95** — Atomic BEEF (already in use by overlay/105 paths).

**Overlay:**
- **BRC-76** — Graph Aware Sync Protocol (GASP) — this is the sync the
repo's roadmap already names; still unimplemented.
- **BRC-136** — Block-Anchored Overlay Synchronization via BASM
(block-aligned sparse Merkle trees) — a newer, block-anchored sync
alternative worth comparing with GASP.
- **BRC-35** — Layered KVStore — still gated in this repo; unchanged.

**Identity-adjacent (worth a look for peck's identity stack):**
- BRC-77/78 (message signing / portable encrypted messages — py-sdk has
BRC-77 already), BRC-140/154/157 (backups), BRC-169 (universal handle
addressing), BRC-145 (registry-free typed content anchor), BRC-146
(access gates), BRC-147/150/159/160 (1Sat ordinals).

### 2.3 SDK floor

`bsv-sdk` is at **2.3.3**; the repo floor is `>=2.1.3`. The full suite
passes on 2.3.3, so the floor can be raised to `>=2.2.0` (or 2.3.x) at the
next release without code changes — recommended so downstream gets the
latest primitives (the two py-sdk bugs in `docs/upstream/`, filed as
py-sdk#158/#159, persist in 2.3.3 and are worked around here already).

## 3. What "modernization" means for this library — prioritized roadmap

Legend: 🟢 done this release · 🟡 next · 🔵 later

### Auth & payments (the web ergonomics core)

- 🟢 **BRC-138 single-use proofs** (`bsv_brc.brc138`) — new module; login
primitive for peck-style apps; interoperable with `@bsv/auth` out of the
box (same default protocol `[2, "bsv auth proof"]`).
- 🟡 **BRC-118 multipart transport in `brc105`** — server-side extraction
(`x-bsv-payment-transports` advertising + multipart body parse) and
client-side switch at 8 KB. Needed the moment agents chain payments
(llm-gateway/peck-host use cases).
- 🟡 **BRC-121 simple 402 profile** — a `x-bsv-*` header-only alternative
that works *without* BRC-103 (the repo's current 105 middleware demands
auth first). Good for public, stateless monetized endpoints.
- 🔵 BRC-120 x402 conformance layer (thin — mostly a no-op alias onto 105
semantics) and BRC-125 PeerPay URI parsing.

### Overlay node

- 🟡 **BRC-96 txid-only BEEF / BRC-158 outpoint BEEF** — bandwidth
optimization for `/submit` and `/lookup` answers when peers opt in.
- 🔵 **BRC-76 GASP peer sync** (roadmap item, still open) and/or **BRC-136
BASM** — the repo's per-topic Merkle state root is already the right
primitive; anchoring the root on-chain + syncing via GASP is the
remaining piece.
- 🔵 BRC-35 KVStore client once a live `tm_kvstore` exists to interop
against.

### Hygiene

- 🟡 Raise `bsv-sdk` floor, add py3.14 to CI matrix (suite already green),
fix the stale BRC-101/108/116 claims (done in docs this release).
- 🔵 File the remaining readiness of `docs/upstream/` reports (both already
filed — #158/#159 — mark README accordingly).

## 4. Decision points for Thomas

1. **BRC-118 vs BRC-121 first?** Both extend `brc105`. BRC-118 = breathing
room for chained payments (agents); BRC-121 = stateless public paywalls
without auth. The repo's README frames 105 as building on 103 — BRC-121
deliberately drops that dependency.
2. **GASP vs BASM** for the sync roadmap — worth one design note before
implementing either.
3. **peck-identity alignment**: `identity.peck.to` is described as "BRC-101
identity resolution" in the architecture docs, but official BRC-101 is
SHIP/SLAP advertisement URLs. Identity resolution in the BRC dir lives
elsewhere (BRC-169 handles; BRC-68 trust anchors; certificates BRC-52).
Worth a correction sweep in peck-docs and identity-services naming.

## 5. What landed in 0.5.0 (this release)

- `bsv_brc.brc138` — BRC-138 single-use signed proofs: create / verify /
check, memory + SQLite single-use stores, Starlette ASGI middleware.
- `crypto.keys.derive_signing_public_key` — the verifier-side counterpart
of BRC-43 signing key derivation.
- Cross-implementation interop harness (`examples/brc138_interop/`) +
pinned regression vectors (`tests/test_brc138_interop.py`) certified
against `@bsv/auth` 0.1.3 / `@bsv/sdk` 2.4.1.
- Stale BRC-101/108/116 claims corrected in README/CLAUDE; documented
gap analysis (this file).
59 changes: 59 additions & 0 deletions examples/brc138_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
BRC-138 single-use signed proof — a login endpoint in one request.

Demo of the module: proves you hold an identity key (no BRC-103 handshake,
no session) in a single request. Shows both sides with one wallet pair —
in production the client signs in a browser wallet and the server verifies
with its own identity key.
"""

from bsv import PrivateKey

from bsv_brc.brc138 import (
AuthProofError,
MemorySingleUseStore,
create_auth_proof,
verify_auth_proof,
)
from bsv_brc.crypto.keys import public_key_from_private

# --- Setup: a client wallet and a server wallet (random keys for the demo) ---
client_key = PrivateKey()
server_key = PrivateKey()
server_pub = public_key_from_private(server_key.serialize()).hex()

# The server's single-use store: consumed nonces are rejected atomically.
# Swap in SqliteSingleUseStore (or any DB with a unique index) for a
# multi-instance deployment.
store = MemorySingleUseStore()

# --- Client: sign a "login" proof toward the server's identity key ---
proof = create_auth_proof(
client_key.serialize(),
server_pub,
"login", # the only action this proof authorizes
)
print("proof:", proof.data.action, "for identity", proof.data.identity_key[:16], "…")

# --- Wire form: a plain JSON object (signature as byte values, per BRC-138) ---
wire = proof.to_dict()
print("wire size:", len(str(wire)), "bytes (expires in 2 min, single use)")

# --- Server: verify (shape → action → freshness → signature → single-use) ---
try:
identity = verify_auth_proof(
server_key.serialize(),
wire,
"login",
single_use_store=store,
)
print("authenticated:", identity == proof.data.identity_key)
except AuthProofError as exc:
print("rejected:", exc)

# --- A replay of the same proof is rejected ---
try:
verify_auth_proof(server_key.serialize(), wire, "login", single_use_store=store)
print("replay ACCEPTED (bug!)")
except AuthProofError as exc:
print("replay rejected:", exc)
50 changes: 50 additions & 0 deletions examples/brc138_interop/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# BRC-138 interop check (Python ⇄ TypeScript reference)

Proves `bsv_brc.brc138` is byte-compatible with the canonical TypeScript
implementation for BRC-138, [`@bsv/auth`](https://www.npmjs.com/package/@bsv/auth)
(which wraps the `@bsv/sdk` BRC-100 wallet interface):

1. Python creates a proof → Node (`verifyAuthProof`) accepts it
2. Python creates a proof with a bound payload → Node accepts it
3. Node (`createAuthProof`) creates a proof → Python (`verify_auth_proof`) accepts it
4. Node creates a proof with a bound binary payload → Python accepts it

The pinned vectors from a certified run live in
`tests/test_brc138_interop.py` (a regression test that needs no Node), so the
byte-compatibility contract stays guarded in CI.

## Setup

```bash
cd examples/brc138_interop
npm install # installs @bsv/auth + @bsv/sdk (see package.json)
cd ../..
python -m venv .venv && source .venv/bin/activate # or reuse an existing venv
pip install -e ".[dev]"
```

## Run the live cross-implementation check

```bash
python examples/brc138_interop/run_interop.py
```

Expect:

```
[1/4] Python proof verified by @bsv/auth (Node): OK
[2/4] Python bound-payload proof verified by @bsv/auth (Node): OK
[3/4] Node proof verified by bsv_brc.brc138 (Python): OK
[4/4] Node bound-payload proof verified by bsv_brc.brc138 (Python): OK
ALL INTEROP CHECKS PASSED
```

## Re-capture pinned vectors (after upstream changes)

```bash
python examples/brc138_interop/capture_vectors.py
```

Paste the printed JSON into `tests/test_brc138_interop.py` (each vector is
re-certified against Node during capture — the script aborts if Node rejects
one).
Loading
Loading