Skip to content
Open
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
2 changes: 1 addition & 1 deletion conformance/runner/reports/report.json
Original file line number Diff line number Diff line change
Expand Up @@ -33835,4 +33835,4 @@
]
}
]
}
}
2 changes: 1 addition & 1 deletion docs/about/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: 'Contributing'
kind: meta
version: '2.0.0'
last_updated: '2026-07-30'
last_verified: '2026-07-30'
last_verified: '2026-08-30'
review_cadence_days: 30
status: stable
tags: [about, contributing, development, community]
Expand Down
2 changes: 1 addition & 1 deletion docs/about/doc-agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: 'Documentation Maintenance'
kind: meta
version: '2.1.0'
last_updated: '2026-07-30'
last_verified: '2026-07-30'
last_verified: '2026-08-30'
review_cadence_days: 30
status: stable
tags: [about, documentation, maintenance, automation]
Expand Down
3 changes: 2 additions & 1 deletion docs/infrastructure/message-box-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ all limits, shared state, BRC-105 pricing, memory evidence, and scaling guidance
| Variable | Required | Description |
| ------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------- |
| NODE_ENV | No | `development`, `staging`, or `production` |
| BSV_NETWORK | No | `mainnet`, `testnet`, `ttn`, or `teratestnet` (default `mainnet`) |
| PORT | No | HTTP/WebSocket port (default 8080; takes precedence) |
| HTTP_PORT | No | Compatibility port fallback |
| HOSTING_DOMAIN | No | Public domain for overlay advertisement (e.g., `http://localhost:8080`) |
Expand Down Expand Up @@ -159,7 +160,7 @@ Migrations tracked in `src/migrations/`:

## Health checks

- `GET /health` reports process liveness without authentication.
- `GET /health` and `GET /healthz` report process liveness without authentication.
- `GET /ready` verifies database connectivity and returns a non-sensitive 503
response while dependencies are unavailable.
- Test an authenticated WebSocket handshake separately when live transport is
Expand Down
2 changes: 1 addition & 1 deletion docs/infrastructure/service-edge-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: 'Public Service Edge Security'
kind: reference
version: '1.0.0'
last_updated: '2026-07-30'
last_verified: '2026-07-30'
last_verified: '2026-08-30'
review_cadence_days: 30
status: stable
tags: [infrastructure, security, cors, rate-limits, authentication, operations]
Expand Down
4 changes: 2 additions & 2 deletions docs/infrastructure/uhrp-server-basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Clients PUT files with authentication, retrieve files via public GET, and query
| Type | Requirement |
| ----------------- | --------------------------------------------------------------------------------------------------- |
| Database | None; filesystem-based storage |
| External services | Wallet Storage (WALLET_STORAGE_URL), ARC (optional for payment transactions) |
| External services | Wallet Storage (WALLET_STORAGE_URL) |
| ts-stack packages | @bsv/sdk, @bsv/auth-express-middleware, @bsv/payment-express-middleware, @bsv/wallet-toolbox-client |

## HTTP endpoints
Expand All @@ -65,7 +65,7 @@ None.
| -------------------------- | -------- | --------------------------------------------------------------------------------------------- |
| PRICE_PER_GB_MO | No | Monthly storage price per GB (e.g., `0.03`) |
| HOSTING_DOMAIN | No | Public domain for server advertisement (e.g., `localhost:8080` or `https://uhrp.example.com`) |
| BSV_NETWORK | No | Target blockchain network (e.g., `mainnet` or `testnet`) |
| BSV_NETWORK | No | `mainnet`, `testnet`, `ttn`, or `teratestnet` (default `mainnet`) |
| WALLET_STORAGE_URL | No | Wallet storage endpoint for key derivation (e.g., `https://store-us-1.bsvb.tech`) |
| SERVER_PRIVATE_KEY | Yes | 256-bit hex private key for server identity |
| HTTP_PORT | No | Express server port (default: 8080) |
Expand Down
32 changes: 17 additions & 15 deletions docs/infrastructure/uhrp-server-cloud-bucket.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ workflows backed by Google Cloud Storage. Static object retrieval is public;
upload, list, find, and renewal require BRC-103 identity. A separate
administrative advertisement endpoint uses a strong Bearer token.

Clients upload files with authentication, retrieve files via public GET, and server continuously advertises hosting capability.
Clients request authenticated uploads, retrieve files via public GET, and use
the bucket notifier to trigger authenticated hosting advertisements.

## When to deploy this

Expand Down Expand Up @@ -69,23 +70,23 @@ None; HTTP-only with background advertising worker.
| NODE_ENV | No | `development`, `staging`, or `production` |
| SERVER_PRIVATE_KEY | Yes | 256-bit hex private key for server identity |
| HOSTING_DOMAIN | No | Public HTTPS domain for advertising (e.g., `https://uhrp-storage.example.com`) |
| BSV_NETWORK | No | Target blockchain network (`main`, `test`, or `regtest`) |
| BSV_NETWORK | No | `mainnet`, `testnet`, `ttn`, or `teratestnet` (default `mainnet`) |
| WALLET_STORAGE_URL | No | Wallet storage endpoint (e.g., `https://store-us-1.bsvb.tech`) |
| PRICE_PER_GB_MO | No | Monthly storage price per GB for billing |
| ENABLE_PAYMENT_MIDDLEWARE | No | Set to `'true'` to require payment for uploads |
| GOOGLE_CLOUD_PROJECT | No | GCP project ID (auto-detected from service account if available) |
| GOOGLE_CLOUD_BUCKET | Yes | Cloud Storage bucket name (e.g., `uhrp-storage-prod`) |
| GOOGLE_APPLICATION_CREDENTIALS | No | Path to service account JSON key (for local/Cloud Run auth) |
| ARC_API_KEY | No | ARC API key for transaction broadcasting (advertising) |
| ADVERTISE_INTERVAL_MS | No | Interval for re-advertising to overlay (default: 3600000ms = 1 hour) |
| BUGSNAG_API_KEY | No | Bugsnag error reporting API key (optional) |
| MIN_HOSTING_MINUTES | No | Minimum requested retention period (default 180 minutes) |
| GCP_PROJECT_ID | Yes* | GCP project used for production signed upload URLs |
| GCP_BUCKET_NAME | Yes | Cloud Storage bucket name (e.g., `uhrp-storage-prod`) |
| GCP_STORAGE_CREDS | Yes* | JSON credentials used for production signed upload URLs; provide through a secret |
| ADMIN_TOKEN | Yes | At least 32 random characters for `/advertise` Bearer auth |
| UHRP_CORS_MODE | No | `public` (default), `allowlist`, or `disabled` |
| UHRP_CORS_ALLOWED_ORIGINS | No | Exact comma-separated origins in allowlist mode |
| UHRP_CORS_ALLOWED_HEADERS | No | Strict comma-separated browser request-header allowlist; omit for additive compatibility |
| UHRP_JSON_MAX_BODY_BYTES | No | JSON body ceiling (default 262144) |
| TRUST_PROXY_HOPS | No | Exact trusted proxy hop count, 0 through 10 |

`GCP_PROJECT_ID` and `GCP_STORAGE_CREDS` are required by the production
signed-upload path; the development path returns a local placeholder URL.

See [Public Service Edge Security](service-edge-security.md#uhrp-cloud-bucket-server)
for full edge controls.

Expand Down Expand Up @@ -118,7 +119,7 @@ gcloud run deploy uhrp-storage \
--image uhrp-storage:latest \
--platform managed \
--region us-central1 \
--set-env-vars SERVER_PRIVATE_KEY=<hex-key>,GOOGLE_CLOUD_BUCKET=uhrp-storage-prod,ENABLE_PAYMENT_MIDDLEWARE=true
--set-env-vars SERVER_PRIVATE_KEY=<hex-key>,GCP_PROJECT_ID=<project>,GCP_BUCKET_NAME=uhrp-storage-prod,ADMIN_TOKEN=<32+-character-token>

# Or deploy with docker-compose (local testing only)
docker compose up -d
Expand Down Expand Up @@ -147,17 +148,18 @@ No database migrations. Google Cloud Storage is the durable source of truth.

- UHRP clients upload/retrieve files using SERVER_PRIVATE_KEY and HOSTING_DOMAIN
- Wallet Storage derives keys, validates payments, manages user accounts
- Background worker advertises UHRP host via SHIP overlay protocol using ARC broadcaster
- Optional Cloud SQL metadata database for query optimization
- Bugsnag integration for production error tracking and monitoring
- The bucket notifier calls the token-protected `/advertise` route, which
publishes the UHRP advertisement through the SDK SHIP broadcaster

## Common pitfalls

- GCP credentials: GOOGLE_APPLICATION_CREDENTIALS must point to valid service account JSON; Cloud Run uses default service account if not set
- Storage bucket policy: Ensure bucket exists and service account has storage.objects.create/get/delete permissions
- Cost management: Monitor storage usage and pricing; use Cloud Storage lifecycle policies for archival
- Payment enforcement: ENABLE_PAYMENT_MIDDLEWARE requires ARC_API_KEY and WALLET_STORAGE_URL; uploads fail if not configured
- Advertising loop: ADVERTISE_INTERVAL_MS should balance frequent updates vs transaction costs; 1 hour is conservative default
- Signed uploads: `GCP_PROJECT_ID`, `GCP_BUCKET_NAME`, and valid JSON in
`GCP_STORAGE_CREDS` must agree; malformed credentials fail URL creation
- Advertising: `ADMIN_TOKEN` must match the bucket notifier and contain at
least 32 characters
- Cloud Run and application request timeouts default to 60 seconds; use direct cloud upload workflows for large objects rather than unbounded application buffering
- Graceful shutdown: Cloud Run sends SIGTERM; ensure all writes complete before exit (transaction broadcasts, metadata flushes)

Expand Down
106 changes: 106 additions & 0 deletions docs/packages/wallet/ecpm-permission-module.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
id: ecpm-permission-module
title: '@bsv/ecpm-permission-module'
kind: package
domain: wallet
npm: '@bsv/ecpm-permission-module'
version: '0.1.0'
last_updated: '2026-08-30'
last_verified: '2026-08-30'
review_cadence_days: 30
status: experimental
tags: ['permissions', 'brc98', 'ecpm', 'cryptography']
repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ecpm-permission-module'
---

# @bsv/ecpm-permission-module

`@bsv/ecpm-permission-module` is the reference `p ecpm` semantic module for
BRC-100 wallet hosts. It applies or removes a wallet-derived scalar from an
arbitrary validated secp256k1 point while retaining the standard
`getPublicKey` request and response shapes.

Use this package when a protocol needs commutative point masking or another
point operation whose base is supplied by the application. Pure BRC-43 can
name a counterparty while deriving the scalar, but ordinary `getPublicKey`
still returns that scalar times the fixed generator; it cannot select the
caller's point as the multiplication base.

## Install

```bash
npm install @bsv/ecpm-permission-module @bsv/wallet-toolbox-client @bsv/sdk
```

## Protocol

Call the existing `getPublicKey` method with this protocol name inside the
normal `[securityLevel, protocolName]` tuple:

```text
p ecpm <apply|remove> <pointHex> <logicalProtocolID>
```

The module reads `keyID`, `counterparty`, `privileged`, `privilegedReason`, and
`seekPermission` from their existing fields. It derives the scalar under
`p ecpm <logicalProtocolID>`; the operation and point are deliberately omitted
so `remove` uses the inverse of the exact scalar selected by `apply`.

```typescript
const masked = await wallet.getPublicKey({
protocolID: [2, `p ecpm apply ${pointHex} mental poker deal`],
keyID: 'deck mask',
counterparty: 'self'
})

const restored = await wallet.getPublicKey({
protocolID: [2, `p ecpm remove ${masked.publicKey} mental poker deal`],
keyID: 'deck mask',
counterparty: 'self'
})
```

## Wallet installation

```typescript
import { createEcpmModule } from '@bsv/ecpm-permission-module'
import { WalletPermissionsManager } from '@bsv/wallet-toolbox-client'

const ecpm = createEcpmModule({
keyDeriver: setup.keyDeriver,
authorize: request => showTrustedWalletPrompt(request),
privilegedKeyDeriver: reason => acquirePrivilegedKeyDeriver(reason)
})

const wallet = new WalletPermissionsManager(setup.wallet, adminOriginator, {
permissionModules: { ecpm }
})
```

The privileged provider is optional. If an application requests
`privileged: true`, the module authorizes the supplied reason before asking the
host for a privileged deriver and fails closed when no provider is available.

## Security and permissions

- Only `getPublicKey` is accepted under `p ecpm`; signing, HMAC, and encryption
calls cannot reuse the ECPM-derived scalar.
- Identity-key and `forSelf` modes are rejected.
- Input points and public-key counterparties must be canonical lowercase,
compressed, finite secp256k1 points.
- Security level 0 ordinary calls do not prompt. Levels 1 and 2 require the
authorization callback; level 2 grants are scoped to the counterparty.
- Every privileged call requires authorization. Cached and concurrent grants
are scoped to the exact approved `privilegedReason`, so a different reason
cannot reuse the approval. `seekPermission: false` fails unless an applicable
grant is already cached.
- The application receives only `{ publicKey }`, never the derived scalar or
either key-derivation provider.

## Module interface

Wallet Toolbox exposes the optional
`PermissionsModule.handleRequest(request, next)` semantic hook. A module can
return the standard BRC-100 result directly, as ECPM does, or call `next` at
most once. Existing `onRequest`/`onResponse` transformation modules remain
compatible.
10 changes: 10 additions & 0 deletions docs/packages/wallet/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ The wallet domain builds on top of [@bsv/sdk](../sdk/bsv-sdk.md). If you only ne
| [@bsv/wallet-toolbox-mobile](./wallet-toolbox-mobile.md) | React Native/mobile-safe wallet and remote storage distribution |
| [@bsv/btms](./btms.md) | UTXO-based token issuance, transfer, burning, and ownership proof validation |
| [@bsv/btms-permission-module](./btms-permission-module.md) | Framework-agnostic BRC-98/99 permission hooks for BTMS token spending with custom UI callback |
| [@bsv/ecpm-permission-module](./ecpm-permission-module.md) | BRC-98 semantic module for applying and removing wallet-derived scalars from secp256k1 points |
| [@bsv/wallet-relay](./wallet-relay.md) | Mobile-to-desktop wallet pairing via QR codes and encrypted WebSocket relay with React components |

## Common Use Cases
Expand Down Expand Up @@ -54,6 +55,13 @@ Use [@bsv/wallet-relay](./wallet-relay.md) for QR pairing. Desktop shows QR, mob

Use [@bsv/btms-permission-module](./btms-permission-module.md) with your custom permission handler (modal, alert, web component, etc.).

### I need wallet-native point multiplication

Use [@bsv/ecpm-permission-module](./ecpm-permission-module.md) to install the
`p ecpm` scheme. It reuses `getPublicKey`, so applications can apply or remove
a BRC-42/43-derived scalar from a named point without extending the BRC-100
wallet interface or exposing the scalar.

## Key Concepts

- **BRC-100 Wallet Interface** — Standard interface implemented by all wallet packages. Apps can work with any wallet (desktop, mobile, hardware) without code changes.
Expand All @@ -66,6 +74,7 @@ Use [@bsv/btms-permission-module](./btms-permission-module.md) with your custom
- **Ownership Proof** — Cryptographic proof of token ownership without revealing private key. Used for collateral, escrow, access control.
- **Relay Session** — Encrypted tunnel between desktop and mobile wallet. QR encodes relay URL + session ID; mobile scans and establishes WebSocket connection.
- **Permission Module** — BRC-98/99 hooks that intercept special operations (token spend, burn) and prompt user via custom callback.
- **Semantic Permission Module** — A BRC-98 module that owns a P-scheme's meaning and returns a conforming result without requiring the underlying BRC-100 method to retain its ordinary behavior.

## Architecture Overview

Expand All @@ -80,6 +89,7 @@ Use [@bsv/btms-permission-module](./btms-permission-module.md) with your custom
| **wallet-toolbox-mobile** | Build tooling | — | Remote |
| **btms** | ✓ | ✓ | ✓ |
| **btms-permission-module** | ✓ | ✓ | ✓ |
| **ecpm-permission-module** | ✓ | ✓ | Host-dependent |
| **wallet-relay** | Server | React components | Supported via relay |

## When to Use Each Package
Expand Down
6 changes: 3 additions & 3 deletions docs/packages/wallet/wallet-toolbox-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ id: pkg-wallet-toolbox-client
title: '@bsv/wallet-toolbox-client'
kind: package
domain: wallet
version: '2.10.4'
last_updated: '2026-08-26'
last_verified: '2026-08-26'
version: '2.11.0'
last_updated: '2026-08-30'
last_verified: '2026-08-30'
review_cadence_days: 30
npm: 'https://www.npmjs.com/package/@bsv/wallet-toolbox-client'
repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/wallet-toolbox/client'
Expand Down
6 changes: 3 additions & 3 deletions docs/packages/wallet/wallet-toolbox-mobile.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ id: pkg-wallet-toolbox-mobile
title: '@bsv/wallet-toolbox-mobile'
kind: package
domain: wallet
version: '2.10.4'
last_updated: '2026-08-26'
last_verified: '2026-08-26'
version: '2.11.0'
last_updated: '2026-08-30'
last_verified: '2026-08-30'
review_cadence_days: 30
npm: 'https://www.npmjs.com/package/@bsv/wallet-toolbox-mobile'
repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/wallet-toolbox/mobile'
Expand Down
Loading
Loading