protect-mcp 0.1.1 → 0.2.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/README.md +126 -60
- package/dist/chunk-D733KAPG.mjs +252 -0
- package/dist/chunk-ZCKNFULF.mjs +613 -0
- package/dist/cli.js +3100 -20
- package/dist/cli.mjs +144 -7
- package/dist/ed25519-EDO4K4EP.mjs +2289 -0
- package/dist/index.d.mts +681 -6
- package/dist/index.d.ts +681 -6
- package/dist/index.js +698 -17
- package/dist/index.mjs +357 -3
- package/dist/utils-IDWBSHJU.mjs +76 -0
- package/package.json +13 -5
- package/dist/chunk-L3QWKSGY.mjs +0 -297
package/README.md
CHANGED
|
@@ -1,44 +1,79 @@
|
|
|
1
1
|
# protect-mcp
|
|
2
2
|
|
|
3
|
-
Security gateway for MCP servers.
|
|
3
|
+
Security gateway for MCP servers. Shadow-mode logs by default, per-tool policies, optional local Ed25519 receipts, and verification-friendly audit output.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Current CLI path:** wrap any stdio MCP server as a transparent proxy. In shadow mode it logs every `tools/call` request and allows everything through. Add a policy file to enforce per-tool rules. Run `protect-mcp init` to generate local signing keys and config so the gateway can also emit signed receipts.
|
|
6
6
|
|
|
7
7
|
## Quick Start
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
#
|
|
10
|
+
# Shadow mode — log every tool call, enforce nothing
|
|
11
11
|
npx protect-mcp -- node my-server.js
|
|
12
12
|
|
|
13
|
-
#
|
|
14
|
-
npx protect-mcp
|
|
13
|
+
# Generate keys + config template for local signing
|
|
14
|
+
npx protect-mcp init
|
|
15
|
+
|
|
16
|
+
# Shadow mode with local signing enabled
|
|
17
|
+
npx protect-mcp --policy protect-mcp.json -- node my-server.js
|
|
18
|
+
|
|
19
|
+
# Enforce mode
|
|
20
|
+
npx protect-mcp --policy protect-mcp.json --enforce -- node my-server.js
|
|
15
21
|
```
|
|
16
22
|
|
|
17
|
-
##
|
|
23
|
+
## What It Does
|
|
18
24
|
|
|
19
25
|
protect-mcp sits between your MCP client and server as a stdio proxy:
|
|
20
26
|
|
|
21
27
|
```
|
|
22
|
-
MCP Client
|
|
28
|
+
MCP Client ←stdin/stdout→ protect-mcp ←stdin/stdout→ your MCP server
|
|
23
29
|
```
|
|
24
30
|
|
|
25
31
|
It intercepts `tools/call` JSON-RPC requests and:
|
|
26
|
-
- **
|
|
27
|
-
- **Enforce mode**: applies policy rules
|
|
32
|
+
- **Shadow mode** (default): logs every tool call and allows everything through
|
|
33
|
+
- **Enforce mode**: applies per-tool policy rules such as `block`, `rate_limit`, and `min_tier`
|
|
34
|
+
- **Optional local signing**: when signing is configured, emits an Ed25519-signed receipt alongside the structured log
|
|
28
35
|
|
|
29
36
|
All other MCP messages (`initialize`, `tools/list`, notifications) pass through transparently.
|
|
30
37
|
|
|
31
|
-
##
|
|
38
|
+
## What Ships Today
|
|
39
|
+
|
|
40
|
+
- **Per-tool policies** — block destructive tools, rate-limit expensive ones, and attach minimum-tier requirements
|
|
41
|
+
- **Structured decision logs** — every decision is emitted to `stderr` with `[PROTECT_MCP]`
|
|
42
|
+
- **Optional local signed receipts** — generated when you run with a policy containing `signing.key_path`
|
|
43
|
+
- **Offline verification** — verify receipts or bundles with `npx @veritasacta/verify`
|
|
44
|
+
- **No account required** — local keys, local policy, local process
|
|
45
|
+
|
|
46
|
+
## Current Capability Boundaries
|
|
32
47
|
|
|
33
|
-
|
|
48
|
+
These are important before you roll this out or talk to users:
|
|
49
|
+
|
|
50
|
+
- **Signing is not automatic on the bare `npx protect-mcp -- ...` path.** That path logs decisions in shadow mode. For local signing, run `npx protect-mcp init` and then start the gateway with the generated policy file.
|
|
51
|
+
- **Tier-aware policy checks are live, but manifest admission is not wired into the default CLI/stdio path.** The CLI defaults sessions to `unknown` unless a host integration calls the admission API programmatically.
|
|
52
|
+
- **Credential config currently validates env-backed credential references and records credential labels in logs/receipts.** Generic per-call injection into arbitrary stdio tools is adapter-specific and is not performed by the default proxy path.
|
|
53
|
+
- **External PDP adapters and audit bundle helpers exist as exported utilities.** They are not yet fully wired into the default CLI path.
|
|
54
|
+
|
|
55
|
+
## Policy File
|
|
34
56
|
|
|
35
57
|
```json
|
|
36
58
|
{
|
|
59
|
+
"default_tier": "unknown",
|
|
37
60
|
"tools": {
|
|
38
|
-
"dangerous_tool": { "
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"*": { "
|
|
61
|
+
"dangerous_tool": { "block": true },
|
|
62
|
+
"admin_tool": { "min_tier": "signed-known", "rate_limit": "5/hour" },
|
|
63
|
+
"read_tool": { "require": "any", "rate_limit": "100/hour" },
|
|
64
|
+
"*": { "rate_limit": "500/hour" }
|
|
65
|
+
},
|
|
66
|
+
"signing": {
|
|
67
|
+
"key_path": "./keys/gateway.json",
|
|
68
|
+
"issuer": "protect-mcp",
|
|
69
|
+
"enabled": true
|
|
70
|
+
},
|
|
71
|
+
"credentials": {
|
|
72
|
+
"internal_api": {
|
|
73
|
+
"inject": "env",
|
|
74
|
+
"name": "INTERNAL_API_KEY",
|
|
75
|
+
"value_env": "INTERNAL_API_KEY"
|
|
76
|
+
}
|
|
42
77
|
}
|
|
43
78
|
}
|
|
44
79
|
```
|
|
@@ -47,11 +82,10 @@ Create a `policy.json`:
|
|
|
47
82
|
|
|
48
83
|
| Field | Values | Description |
|
|
49
84
|
|-------|--------|-------------|
|
|
50
|
-
| `require` | `"gateway"`, `"any"`, `"none"` | Identity requirement (metadata only in v1 — not enforced until v2 SSE transport) |
|
|
51
|
-
| `rate_limit` | `"N/unit"` | Rate limit (e.g. `"5/hour"`, `"100/day"`, `"10/minute"`) |
|
|
52
85
|
| `block` | `true` | Explicitly block this tool |
|
|
53
|
-
|
|
54
|
-
|
|
86
|
+
| `require` | `"any"`, `"none"` | Basic access requirement |
|
|
87
|
+
| `min_tier` | `"unknown"`, `"signed-known"`, `"evidenced"`, `"privileged"` | Minimum tier required if your host sets admission state |
|
|
88
|
+
| `rate_limit` | `"N/unit"` | Rate limit (e.g. `"5/hour"`, `"100/day"`) |
|
|
55
89
|
|
|
56
90
|
Tool names match exactly, with `"*"` as a wildcard fallback.
|
|
57
91
|
|
|
@@ -68,7 +102,7 @@ Add to `claude_desktop_config.json`:
|
|
|
68
102
|
"command": "npx",
|
|
69
103
|
"args": [
|
|
70
104
|
"-y", "protect-mcp",
|
|
71
|
-
"--policy", "/path/to/
|
|
105
|
+
"--policy", "/path/to/protect-mcp.json",
|
|
72
106
|
"--enforce",
|
|
73
107
|
"--", "node", "my-server.js"
|
|
74
108
|
]
|
|
@@ -79,63 +113,95 @@ Add to `claude_desktop_config.json`:
|
|
|
79
113
|
|
|
80
114
|
### Cursor / VS Code
|
|
81
115
|
|
|
82
|
-
Same pattern — replace the server command with protect-mcp wrapping it.
|
|
83
|
-
|
|
84
|
-
## Decision Logs
|
|
85
|
-
|
|
86
|
-
Every tool call emits a structured JSON log to stderr:
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
[PROTECT_MCP] {"v":1,"tool":"dangerous_tool","decision":"deny","reason_code":"rate_limit_exceeded","policy_digest":"a1b2c3d4","request_id":"req_abc123","timestamp":1710000000,"mode":"enforce","rate_limit_remaining":0}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Log Fields
|
|
93
|
-
|
|
94
|
-
| Field | Description |
|
|
95
|
-
|-------|-------------|
|
|
96
|
-
| `v` | Schema version (always `1`) |
|
|
97
|
-
| `tool` | Tool name that was called |
|
|
98
|
-
| `decision` | `"allow"` or `"deny"` |
|
|
99
|
-
| `reason_code` | `"policy_allow"`, `"policy_block"`, `"rate_limit_exceeded"`, `"observe_mode"`, `"default_allow"` |
|
|
100
|
-
| `policy_digest` | SHA-256 prefix of the policy file |
|
|
101
|
-
| `request_id` | Unique request identifier |
|
|
102
|
-
| `timestamp` | Unix timestamp (ms) |
|
|
103
|
-
| `mode` | `"observe"` or `"enforce"` |
|
|
104
|
-
| `rate_limit_remaining` | Remaining rate limit budget (if applicable) |
|
|
105
|
-
|
|
106
|
-
These are **decision logs**, not signed receipts. Cryptographically signed receipts require the ScopeBlind API (v2).
|
|
116
|
+
Same pattern — replace the server command with `protect-mcp` wrapping it.
|
|
107
117
|
|
|
108
118
|
## CLI Options
|
|
109
119
|
|
|
110
120
|
```
|
|
111
121
|
protect-mcp [options] -- <command> [args...]
|
|
122
|
+
protect-mcp init
|
|
123
|
+
|
|
124
|
+
Commands:
|
|
125
|
+
init Generate Ed25519 keypair + config template
|
|
112
126
|
|
|
113
127
|
Options:
|
|
114
|
-
--policy <path> Policy JSON file
|
|
115
|
-
--slug <slug>
|
|
116
|
-
--enforce Enable enforcement mode (default:
|
|
128
|
+
--policy <path> Policy/config JSON file
|
|
129
|
+
--slug <slug> Service identifier for logs/receipts
|
|
130
|
+
--enforce Enable enforcement mode (default: shadow)
|
|
117
131
|
--verbose Enable debug logging
|
|
118
132
|
--help Show help
|
|
119
133
|
```
|
|
120
134
|
|
|
121
|
-
## Programmatic
|
|
135
|
+
## Programmatic Hooks
|
|
136
|
+
|
|
137
|
+
The library also exposes the primitives that are not yet wired into the default CLI path:
|
|
122
138
|
|
|
123
139
|
```typescript
|
|
124
|
-
import {
|
|
140
|
+
import {
|
|
141
|
+
ProtectGateway,
|
|
142
|
+
loadPolicy,
|
|
143
|
+
evaluateTier,
|
|
144
|
+
meetsMinTier,
|
|
145
|
+
resolveCredential,
|
|
146
|
+
initSigning,
|
|
147
|
+
signDecision,
|
|
148
|
+
queryExternalPDP,
|
|
149
|
+
buildDecisionContext,
|
|
150
|
+
createAuditBundle,
|
|
151
|
+
} from 'protect-mcp';
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Use these if you want to add:
|
|
155
|
+
- manifest admission before a session starts
|
|
156
|
+
- an external PDP (OPA, Cerbos, or a generic HTTP webhook)
|
|
157
|
+
- custom credential-brokered integrations
|
|
158
|
+
- audit bundle export around your own receipt store
|
|
159
|
+
|
|
160
|
+
## Decision Logs and Receipts
|
|
161
|
+
|
|
162
|
+
Every tool call emits structured JSON to `stderr`:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
[PROTECT_MCP] {"v":2,"tool":"read_file","decision":"allow","reason_code":"observe_mode","policy_digest":"none","mode":"shadow","timestamp":1710000000}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
When signing is configured, a signed receipt follows:
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
[PROTECT_MCP_RECEIPT] {"v":2,"type":"decision_receipt","algorithm":"ed25519","kid":"...","issuer":"protect-mcp","issued_at":"2026-03-22T00:00:00Z","payload":{"tool":"read_file","decision":"allow","policy_digest":"...","mode":"shadow","request_id":"..."},"signature":"..."}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Verify with the CLI: `npx @veritasacta/verify receipt.json`
|
|
175
|
+
Verify in browser: [scopeblind.com/verify](https://scopeblind.com/verify)
|
|
125
176
|
|
|
126
|
-
|
|
177
|
+
## Audit Bundles
|
|
127
178
|
|
|
128
|
-
|
|
129
|
-
command: 'node',
|
|
130
|
-
args: ['my-server.js'],
|
|
131
|
-
policy,
|
|
132
|
-
policyDigest: digest,
|
|
133
|
-
enforce: true,
|
|
134
|
-
});
|
|
179
|
+
The package exports a helper for self-contained audit bundles:
|
|
135
180
|
|
|
136
|
-
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"format": "scopeblind:audit-bundle",
|
|
184
|
+
"version": 1,
|
|
185
|
+
"tenant": "my-service",
|
|
186
|
+
"receipts": ["..."],
|
|
187
|
+
"verification": {
|
|
188
|
+
"algorithm": "ed25519",
|
|
189
|
+
"signing_keys": ["..."]
|
|
190
|
+
}
|
|
191
|
+
}
|
|
137
192
|
```
|
|
138
193
|
|
|
194
|
+
Use `createAuditBundle()` around your own collected signed receipts.
|
|
195
|
+
|
|
196
|
+
## Philosophy
|
|
197
|
+
|
|
198
|
+
- **Shadow first.** See what agents are doing before you enforce anything.
|
|
199
|
+
- **Receipts beat dashboard-only logs.** Signed artifacts should be independently verifiable.
|
|
200
|
+
- **Keep the claims tight.** The default CLI path does not yet do everything the long-term architecture will support.
|
|
201
|
+
- **Layer on top of existing auth.** Don't rip out your stack just to add control and evidence.
|
|
202
|
+
|
|
139
203
|
## License
|
|
140
204
|
|
|
141
|
-
FSL-1.1-MIT
|
|
205
|
+
FSL-1.1-MIT — free to use, converts to full MIT after 2 years.
|
|
206
|
+
|
|
207
|
+
[scopeblind.com](https://scopeblind.com) · [npm](https://www.npmjs.com/package/protect-mcp) · [GitHub](https://github.com/tomjwxf/scopeblind-gateway)
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// node_modules/@noble/hashes/esm/cryptoNode.js
|
|
2
|
+
import * as nc from "crypto";
|
|
3
|
+
var crypto = nc && typeof nc === "object" && "webcrypto" in nc ? nc.webcrypto : nc && typeof nc === "object" && "randomBytes" in nc ? nc : void 0;
|
|
4
|
+
|
|
5
|
+
// node_modules/@noble/hashes/esm/utils.js
|
|
6
|
+
function isBytes(a) {
|
|
7
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
8
|
+
}
|
|
9
|
+
function anumber(n) {
|
|
10
|
+
if (!Number.isSafeInteger(n) || n < 0)
|
|
11
|
+
throw new Error("positive integer expected, got " + n);
|
|
12
|
+
}
|
|
13
|
+
function abytes(b, ...lengths) {
|
|
14
|
+
if (!isBytes(b))
|
|
15
|
+
throw new Error("Uint8Array expected");
|
|
16
|
+
if (lengths.length > 0 && !lengths.includes(b.length))
|
|
17
|
+
throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
|
|
18
|
+
}
|
|
19
|
+
function ahash(h) {
|
|
20
|
+
if (typeof h !== "function" || typeof h.create !== "function")
|
|
21
|
+
throw new Error("Hash should be wrapped by utils.createHasher");
|
|
22
|
+
anumber(h.outputLen);
|
|
23
|
+
anumber(h.blockLen);
|
|
24
|
+
}
|
|
25
|
+
function aexists(instance, checkFinished = true) {
|
|
26
|
+
if (instance.destroyed)
|
|
27
|
+
throw new Error("Hash instance has been destroyed");
|
|
28
|
+
if (checkFinished && instance.finished)
|
|
29
|
+
throw new Error("Hash#digest() has already been called");
|
|
30
|
+
}
|
|
31
|
+
function aoutput(out, instance) {
|
|
32
|
+
abytes(out);
|
|
33
|
+
const min = instance.outputLen;
|
|
34
|
+
if (out.length < min) {
|
|
35
|
+
throw new Error("digestInto() expects output buffer of length at least " + min);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function u8(arr) {
|
|
39
|
+
return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
40
|
+
}
|
|
41
|
+
function u32(arr) {
|
|
42
|
+
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
|
|
43
|
+
}
|
|
44
|
+
function clean(...arrays) {
|
|
45
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
46
|
+
arrays[i].fill(0);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function createView(arr) {
|
|
50
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
51
|
+
}
|
|
52
|
+
function rotr(word, shift) {
|
|
53
|
+
return word << 32 - shift | word >>> shift;
|
|
54
|
+
}
|
|
55
|
+
function rotl(word, shift) {
|
|
56
|
+
return word << shift | word >>> 32 - shift >>> 0;
|
|
57
|
+
}
|
|
58
|
+
var isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
|
|
59
|
+
function byteSwap(word) {
|
|
60
|
+
return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
|
|
61
|
+
}
|
|
62
|
+
var swap8IfBE = isLE ? (n) => n : (n) => byteSwap(n);
|
|
63
|
+
var byteSwapIfBE = swap8IfBE;
|
|
64
|
+
function byteSwap32(arr) {
|
|
65
|
+
for (let i = 0; i < arr.length; i++) {
|
|
66
|
+
arr[i] = byteSwap(arr[i]);
|
|
67
|
+
}
|
|
68
|
+
return arr;
|
|
69
|
+
}
|
|
70
|
+
var swap32IfBE = isLE ? (u) => u : byteSwap32;
|
|
71
|
+
var hasHexBuiltin = /* @__PURE__ */ (() => (
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
|
|
74
|
+
))();
|
|
75
|
+
var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
76
|
+
function bytesToHex(bytes) {
|
|
77
|
+
abytes(bytes);
|
|
78
|
+
if (hasHexBuiltin)
|
|
79
|
+
return bytes.toHex();
|
|
80
|
+
let hex = "";
|
|
81
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
82
|
+
hex += hexes[bytes[i]];
|
|
83
|
+
}
|
|
84
|
+
return hex;
|
|
85
|
+
}
|
|
86
|
+
var asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
|
|
87
|
+
function asciiToBase16(ch) {
|
|
88
|
+
if (ch >= asciis._0 && ch <= asciis._9)
|
|
89
|
+
return ch - asciis._0;
|
|
90
|
+
if (ch >= asciis.A && ch <= asciis.F)
|
|
91
|
+
return ch - (asciis.A - 10);
|
|
92
|
+
if (ch >= asciis.a && ch <= asciis.f)
|
|
93
|
+
return ch - (asciis.a - 10);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
function hexToBytes(hex) {
|
|
97
|
+
if (typeof hex !== "string")
|
|
98
|
+
throw new Error("hex string expected, got " + typeof hex);
|
|
99
|
+
if (hasHexBuiltin)
|
|
100
|
+
return Uint8Array.fromHex(hex);
|
|
101
|
+
const hl = hex.length;
|
|
102
|
+
const al = hl / 2;
|
|
103
|
+
if (hl % 2)
|
|
104
|
+
throw new Error("hex string expected, got unpadded hex of length " + hl);
|
|
105
|
+
const array = new Uint8Array(al);
|
|
106
|
+
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
|
|
107
|
+
const n1 = asciiToBase16(hex.charCodeAt(hi));
|
|
108
|
+
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
|
|
109
|
+
if (n1 === void 0 || n2 === void 0) {
|
|
110
|
+
const char = hex[hi] + hex[hi + 1];
|
|
111
|
+
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
|
|
112
|
+
}
|
|
113
|
+
array[ai] = n1 * 16 + n2;
|
|
114
|
+
}
|
|
115
|
+
return array;
|
|
116
|
+
}
|
|
117
|
+
var nextTick = async () => {
|
|
118
|
+
};
|
|
119
|
+
async function asyncLoop(iters, tick, cb) {
|
|
120
|
+
let ts = Date.now();
|
|
121
|
+
for (let i = 0; i < iters; i++) {
|
|
122
|
+
cb(i);
|
|
123
|
+
const diff = Date.now() - ts;
|
|
124
|
+
if (diff >= 0 && diff < tick)
|
|
125
|
+
continue;
|
|
126
|
+
await nextTick();
|
|
127
|
+
ts += diff;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function utf8ToBytes(str) {
|
|
131
|
+
if (typeof str !== "string")
|
|
132
|
+
throw new Error("string expected");
|
|
133
|
+
return new Uint8Array(new TextEncoder().encode(str));
|
|
134
|
+
}
|
|
135
|
+
function bytesToUtf8(bytes) {
|
|
136
|
+
return new TextDecoder().decode(bytes);
|
|
137
|
+
}
|
|
138
|
+
function toBytes(data) {
|
|
139
|
+
if (typeof data === "string")
|
|
140
|
+
data = utf8ToBytes(data);
|
|
141
|
+
abytes(data);
|
|
142
|
+
return data;
|
|
143
|
+
}
|
|
144
|
+
function kdfInputToBytes(data) {
|
|
145
|
+
if (typeof data === "string")
|
|
146
|
+
data = utf8ToBytes(data);
|
|
147
|
+
abytes(data);
|
|
148
|
+
return data;
|
|
149
|
+
}
|
|
150
|
+
function concatBytes(...arrays) {
|
|
151
|
+
let sum = 0;
|
|
152
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
153
|
+
const a = arrays[i];
|
|
154
|
+
abytes(a);
|
|
155
|
+
sum += a.length;
|
|
156
|
+
}
|
|
157
|
+
const res = new Uint8Array(sum);
|
|
158
|
+
for (let i = 0, pad = 0; i < arrays.length; i++) {
|
|
159
|
+
const a = arrays[i];
|
|
160
|
+
res.set(a, pad);
|
|
161
|
+
pad += a.length;
|
|
162
|
+
}
|
|
163
|
+
return res;
|
|
164
|
+
}
|
|
165
|
+
function checkOpts(defaults, opts) {
|
|
166
|
+
if (opts !== void 0 && {}.toString.call(opts) !== "[object Object]")
|
|
167
|
+
throw new Error("options should be object or undefined");
|
|
168
|
+
const merged = Object.assign(defaults, opts);
|
|
169
|
+
return merged;
|
|
170
|
+
}
|
|
171
|
+
var Hash = class {
|
|
172
|
+
};
|
|
173
|
+
function createHasher(hashCons) {
|
|
174
|
+
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
|
|
175
|
+
const tmp = hashCons();
|
|
176
|
+
hashC.outputLen = tmp.outputLen;
|
|
177
|
+
hashC.blockLen = tmp.blockLen;
|
|
178
|
+
hashC.create = () => hashCons();
|
|
179
|
+
return hashC;
|
|
180
|
+
}
|
|
181
|
+
function createOptHasher(hashCons) {
|
|
182
|
+
const hashC = (msg, opts) => hashCons(opts).update(toBytes(msg)).digest();
|
|
183
|
+
const tmp = hashCons({});
|
|
184
|
+
hashC.outputLen = tmp.outputLen;
|
|
185
|
+
hashC.blockLen = tmp.blockLen;
|
|
186
|
+
hashC.create = (opts) => hashCons(opts);
|
|
187
|
+
return hashC;
|
|
188
|
+
}
|
|
189
|
+
function createXOFer(hashCons) {
|
|
190
|
+
const hashC = (msg, opts) => hashCons(opts).update(toBytes(msg)).digest();
|
|
191
|
+
const tmp = hashCons({});
|
|
192
|
+
hashC.outputLen = tmp.outputLen;
|
|
193
|
+
hashC.blockLen = tmp.blockLen;
|
|
194
|
+
hashC.create = (opts) => hashCons(opts);
|
|
195
|
+
return hashC;
|
|
196
|
+
}
|
|
197
|
+
var wrapConstructor = createHasher;
|
|
198
|
+
var wrapConstructorWithOpts = createOptHasher;
|
|
199
|
+
var wrapXOFConstructorWithOpts = createXOFer;
|
|
200
|
+
function randomBytes(bytesLength = 32) {
|
|
201
|
+
if (crypto && typeof crypto.getRandomValues === "function") {
|
|
202
|
+
return crypto.getRandomValues(new Uint8Array(bytesLength));
|
|
203
|
+
}
|
|
204
|
+
if (crypto && typeof crypto.randomBytes === "function") {
|
|
205
|
+
return Uint8Array.from(crypto.randomBytes(bytesLength));
|
|
206
|
+
}
|
|
207
|
+
throw new Error("crypto.getRandomValues must be defined");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export {
|
|
211
|
+
isBytes,
|
|
212
|
+
anumber,
|
|
213
|
+
abytes,
|
|
214
|
+
ahash,
|
|
215
|
+
aexists,
|
|
216
|
+
aoutput,
|
|
217
|
+
u8,
|
|
218
|
+
u32,
|
|
219
|
+
clean,
|
|
220
|
+
createView,
|
|
221
|
+
rotr,
|
|
222
|
+
rotl,
|
|
223
|
+
isLE,
|
|
224
|
+
byteSwap,
|
|
225
|
+
swap8IfBE,
|
|
226
|
+
byteSwapIfBE,
|
|
227
|
+
byteSwap32,
|
|
228
|
+
swap32IfBE,
|
|
229
|
+
bytesToHex,
|
|
230
|
+
hexToBytes,
|
|
231
|
+
nextTick,
|
|
232
|
+
asyncLoop,
|
|
233
|
+
utf8ToBytes,
|
|
234
|
+
bytesToUtf8,
|
|
235
|
+
toBytes,
|
|
236
|
+
kdfInputToBytes,
|
|
237
|
+
concatBytes,
|
|
238
|
+
checkOpts,
|
|
239
|
+
Hash,
|
|
240
|
+
createHasher,
|
|
241
|
+
createOptHasher,
|
|
242
|
+
createXOFer,
|
|
243
|
+
wrapConstructor,
|
|
244
|
+
wrapConstructorWithOpts,
|
|
245
|
+
wrapXOFConstructorWithOpts,
|
|
246
|
+
randomBytes
|
|
247
|
+
};
|
|
248
|
+
/*! Bundled license information:
|
|
249
|
+
|
|
250
|
+
@noble/hashes/esm/utils.js:
|
|
251
|
+
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
252
|
+
*/
|