@btx-tools/challenges-sdk 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/dist/index.cjs +711 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +406 -0
- package/dist/index.d.ts +406 -0
- package/dist/index.js +702 -0
- package/dist/index.js.map +1 -0
- package/package.json +76 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 visitor-code
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# @btx/challenges-sdk
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
|
|
5
|
+
TypeScript SDK for **BTX service challenges** — chain-anchored proof-of-work admission control for APIs, agent gateways, and form submissions.
|
|
6
|
+
|
|
7
|
+
> ⚠️ **Status**: 0.0.1 pre-release. Day 2.5 shipped: RPC + pure-JS solver, cross-validated byte-equal against btxd's own pinned test vectors. See [CHANGELOG](https://github.com/btx-tools/btx-challenges-sdk/blob/main/CHANGELOG.md).
|
|
8
|
+
|
|
9
|
+
## What is this?
|
|
10
|
+
|
|
11
|
+
[BTX](https://btx.dev) is a post-quantum settlement chain that exposes a unique admission-control primitive: domain-bound MatMul work proofs that you can use to gate any HTTP endpoint, MCP tool call, or anonymous form submission.
|
|
12
|
+
|
|
13
|
+
Issue a challenge → client solves a ~1–4 second matrix-multiplication puzzle → server redeems the proof atomically (no replays). The work is anchored to the BTX chain — tamper-proof, no centralized issuer needed.
|
|
14
|
+
|
|
15
|
+
**Use cases**:
|
|
16
|
+
|
|
17
|
+
- 🤖 Gate AI inference APIs without a CAPTCHA
|
|
18
|
+
- 🛡️ Per-tool-call proof-of-work for MCP / agent gateways
|
|
19
|
+
- 📝 Anonymous form submission rate-limiting
|
|
20
|
+
- 🚦 Replace hCaptcha / reCAPTCHA with chain-anchored proof
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @btx/challenges-sdk
|
|
26
|
+
# or
|
|
27
|
+
pnpm add @btx/challenges-sdk
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quickstart
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { BtxChallengeClient } from '@btx/challenges-sdk';
|
|
34
|
+
|
|
35
|
+
const client = new BtxChallengeClient({
|
|
36
|
+
rpcUrl: 'http://127.0.0.1:19332',
|
|
37
|
+
rpcAuth: { user: 'rpcuser', pass: 'rpcpass' },
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Server: issue a challenge bound to the requested resource
|
|
41
|
+
const challenge = await client.issue({
|
|
42
|
+
purpose: 'ai_inference_gate',
|
|
43
|
+
resource: 'model:gpt-x|route:/v1/generate',
|
|
44
|
+
subject: 'tenant:abc123',
|
|
45
|
+
target_solve_time_s: 2,
|
|
46
|
+
expires_in_s: 60,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// ... ship challenge to client; client solves locally and returns (nonce, digest) ...
|
|
50
|
+
|
|
51
|
+
// Server: verify-and-consume atomically (anti-replay admission)
|
|
52
|
+
const result = await client.redeem(challenge, nonce64_hex, digest_hex);
|
|
53
|
+
|
|
54
|
+
if (result.valid && result.reason === 'ok') {
|
|
55
|
+
// Run the expensive action
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Security
|
|
60
|
+
|
|
61
|
+
### HTTPS / TLS
|
|
62
|
+
|
|
63
|
+
Basic-auth credentials are sent on every RPC call. **Use HTTPS** (or a localhost-only deployment) when btxd's RPC port is exposed beyond `127.0.0.1`.
|
|
64
|
+
|
|
65
|
+
Recommended terminations:
|
|
66
|
+
|
|
67
|
+
- **stunnel**, **nginx**, or **Caddy** in front of btxd
|
|
68
|
+
- **Cloudflare Tunnel** for remote operator access
|
|
69
|
+
- Never expose btxd's RPC port (default `19332`) directly to the public internet
|
|
70
|
+
|
|
71
|
+
The SDK does NOT enforce HTTPS — that's a deployment concern. If you set `rpcUrl: 'http://example.com:19332'` from a production service, the SDK will happily transmit your credentials in plaintext.
|
|
72
|
+
|
|
73
|
+
### Error handling
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import {
|
|
77
|
+
BtxError, // base class — all SDK errors extend this
|
|
78
|
+
BtxRpcError, // btxd returned a JSON-RPC error envelope
|
|
79
|
+
BtxHttpError, // non-2xx HTTP status
|
|
80
|
+
BtxParseError, // 2xx but body wasn't valid JSON
|
|
81
|
+
BtxTimeoutError, // request exceeded timeoutMs
|
|
82
|
+
BtxNetworkError, // DNS/TCP/TLS-level failure
|
|
83
|
+
} from '@btx/challenges-sdk';
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
await client.redeem(challenge, nonce, digest);
|
|
87
|
+
} catch (err) {
|
|
88
|
+
if (err instanceof BtxRpcError && err.code === -8) {
|
|
89
|
+
// btxd rejected the request shape
|
|
90
|
+
} else if (err instanceof BtxTimeoutError) {
|
|
91
|
+
// user took too long to solve
|
|
92
|
+
} else if (err instanceof BtxError) {
|
|
93
|
+
// any other SDK-originated error
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Error response bodies are scanned and `Authorization: Basic <token>` patterns are redacted before storage — safe to log.
|
|
99
|
+
|
|
100
|
+
## API
|
|
101
|
+
|
|
102
|
+
### `BtxChallengeClient`
|
|
103
|
+
|
|
104
|
+
| Method | RPC | Description |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `issue(params)` | `getmatmulservicechallenge` | Issue a fresh challenge bound to (purpose, resource, subject). |
|
|
107
|
+
| `verify(...)` | `verifymatmulserviceproof` | Stateless verify. Does NOT consume the challenge. |
|
|
108
|
+
| `redeem(...)` | `redeemmatmulserviceproof` | **Atomic verify + consume**. Use for admission control. |
|
|
109
|
+
| `verifyBatch(entries)` | `verifymatmulserviceproofs` | Batch (1–256) verify. No consumption. |
|
|
110
|
+
| `redeemBatch(entries)` | `redeemmatmulserviceproofs` | Batch verify + consume, sequential. |
|
|
111
|
+
| `solve(challenge)` | `solvematmulservicechallenge` | Server-side solver (fixtures + tests). |
|
|
112
|
+
| `call(method, params)` | (any) | Low-level escape hatch. |
|
|
113
|
+
|
|
114
|
+
### `Solver`
|
|
115
|
+
|
|
116
|
+
Three modes:
|
|
117
|
+
|
|
118
|
+
- **`'rpc'`** — delegates to btxd's `solvematmulservicechallenge` RPC. Server-side / Node only. Fast (sub-second to a few seconds) on a dedicated non-mining node — see the deployment note below.
|
|
119
|
+
- **`'pure-js'`** — solves locally in pure TypeScript with `@noble/hashes` SHA-256. Browser-compatible. Slow at production difficulty (see the performance section); calibrate via `target_solve_time_s` for browser use.
|
|
120
|
+
- **`'auto'`** (default) — picks `'rpc'` if `opts.rpcClient` is provided, else `'pure-js'`.
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import { BtxChallengeClient, Solver } from '@btx/challenges-sdk';
|
|
124
|
+
|
|
125
|
+
// Server-side (RPC mode): delegates the solve to btxd
|
|
126
|
+
const client = new BtxChallengeClient({ rpcUrl: '...', rpcAuth: { ... } });
|
|
127
|
+
const proof = await Solver.solve(challenge, { mode: 'rpc', rpcClient: client });
|
|
128
|
+
|
|
129
|
+
// Browser / no-RPC (pure-JS mode): solves locally, no node required
|
|
130
|
+
const proof = await Solver.solve(challenge, {
|
|
131
|
+
mode: 'pure-js',
|
|
132
|
+
pureJs: { maxTries: 5_000 }, // cap on attempts before giving up
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// 'auto' (default) — picks rpc if a client is passed, else pure-js
|
|
136
|
+
const proof = await Solver.solve(challenge, { rpcClient: client });
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### Algorithm correctness
|
|
140
|
+
|
|
141
|
+
The pure-JS solver is a direct port of the canonical CPU path from `btxd v0.29.7 src/matmul/`. We cross-validate against 5 pinned golden vectors lifted from btxd's own test suite — see `tests/unit/matmul/btxd-vectors.test.ts`. Match is byte-equal for:
|
|
142
|
+
|
|
143
|
+
- `fromSeedRect(zero, 8)` — `matrix_from_seed_deterministic`
|
|
144
|
+
- `deriveNoiseSeed(TAG_EL, zero_sigma)` — `noise_derived_seed_pinned_EL`
|
|
145
|
+
- `noise.generate(zero_sigma, 4, 2)` E_L + E_R — `noise_EL_pinned_elements` / `noise_ER_pinned_elements`
|
|
146
|
+
- `canonicalMatMul(n=8, b=4)` transcript_hash — `canonical_matmul_n8_b4_pinned_transcript`
|
|
147
|
+
- Live `deriveSigma` (2 nonces) — `verifymatmulserviceproof.proof.sigma` from a real btxd
|
|
148
|
+
|
|
149
|
+
Plus 125 internal unit tests covering field arithmetic, matrix ops, header serialization, and solver dispatch.
|
|
150
|
+
|
|
151
|
+
#### ⚠️ Deployment note — RPC mode against a mining btxd
|
|
152
|
+
|
|
153
|
+
btxd's service-challenge solver shares the matmul backend with block-template mining. On a node that's actively mining, `solvematmulservicechallenge` queues behind block work and can take **15+ minutes** per call — measured 2026-05-20 on a production mining rental, where the solve RPC didn't return even after `btx-cli`'s own 15-minute transient-error timeout fired.
|
|
154
|
+
|
|
155
|
+
For RPC mode at advertised latency (~1–4 seconds), point it at a **dedicated btxd** that is NOT mining (e.g., a $5/mo DO droplet with `gen=0` in `btx.conf`). The SDK itself works fine — the bottleneck is the upstream solver service-sharing.
|
|
156
|
+
|
|
157
|
+
## Performance
|
|
158
|
+
|
|
159
|
+
Pure-JS solver bench at production matmul shape (n=512, b=16, r=8) on M-series Mac / Node 22 (2026-05-21):
|
|
160
|
+
|
|
161
|
+
| Statistic | Wall-clock per attempt |
|
|
162
|
+
|---|---|
|
|
163
|
+
| mean | **4.6 s** |
|
|
164
|
+
| median | 4.6 s |
|
|
165
|
+
| min / max | 4.6 / 4.7 s |
|
|
166
|
+
|
|
167
|
+
`mul` and the `dot` accumulator use `bigint` because the worst-case M31 product (`(2^31-1)^2 ≈ 2^62`) exceeds `Number`'s 2^53 precision. The `bigint`-bounded inner loop is the dominant cost.
|
|
168
|
+
|
|
169
|
+
Expected end-to-end solve time depends on challenge difficulty. At btxd's lowest service-challenge difficulty (`target_solve_time_s = min_solve_time_s = 0.001`), per-attempt success ≈ 1.3·10⁻³, so expected ≈ 770 attempts ≈ **1 hour** wall-clock. **Default difficulty is too slow for online browser use.** Workable today for:
|
|
170
|
+
|
|
171
|
+
- Server-side gating where you control difficulty (calibrate via `target_solve_time_s` for your target user wait)
|
|
172
|
+
- Backend cron / batch jobs
|
|
173
|
+
- Examples + demos with manually-issued low-difficulty challenges
|
|
174
|
+
|
|
175
|
+
Day 2.6 will add a WASM port of the matmul kernel + the `field.mul`/`field.dot` hot loops, targeting a 10× speed-up.
|
|
176
|
+
|
|
177
|
+
Reproduce the bench:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npx tsx packages/core/tests/perf/solver-bench.ts 10 # 10 attempts
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
> **Cross-engine note**: bench captured on **Node 22 / V8 / M-series Mac arm64** (2026-05-21). `bigint` performance varies significantly by JS engine — Bun, Deno, Firefox SpiderMonkey, Safari JavaScriptCore are untested. If you run the SDK in those environments, please file an issue with your `solver-bench.ts` output so we can track real-world numbers across engines.
|
|
184
|
+
|
|
185
|
+
## Roadmap
|
|
186
|
+
|
|
187
|
+
| Status | Item |
|
|
188
|
+
|---|---|
|
|
189
|
+
| ✅ | Day 1: RPC client + types + audit Wave A/B/C fixes |
|
|
190
|
+
| ✅ | Day 2: Solver class with mode dispatch (RPC mode ships) |
|
|
191
|
+
| ✅ | Day 2.5: Pure-JS MatMul solver port, cross-validated against btxd goldens |
|
|
192
|
+
| ⏳ | Day 2.6: WASM port of matmul kernel (perf) |
|
|
193
|
+
| ⏳ | Day 3: Express / Fastify / Hono middleware (separate sub-packages) |
|
|
194
|
+
| ⏳ | Day 4: Browser demo + Node examples |
|
|
195
|
+
| ⏳ | Day 5-6: `@btx/mcp-gateway` companion package |
|
|
196
|
+
| ⏳ | Day 7-8: Docs + npm publish |
|
|
197
|
+
| ⏳ | Day 9: Findings + handoff |
|
|
198
|
+
|
|
199
|
+
## Testing
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
pnpm test # all tests
|
|
203
|
+
pnpm test:unit # msw-mocked HTTP only (fast)
|
|
204
|
+
pnpm test:integration # live btxd via SSH (requires fleet access)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The integration test target is `btx-iowa` by default — change `SSH_TARGET` in `tests/integration/smoke.test.ts` to retarget any healthy at-tip BTX node.
|
|
208
|
+
|
|
209
|
+
## Links
|
|
210
|
+
|
|
211
|
+
- [BTX dev portal](https://btx.dev/develop/)
|
|
212
|
+
- [Service-challenges RPC reference](https://btx.dev/docs/rpc/service-challenges)
|
|
213
|
+
- [Service-challenges integration guide](https://btx.dev/docs/guides/service-challenges)
|
|
214
|
+
- [BTX node source](https://github.com/btxchain/btx)
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT
|