@7h3/protocol 0.4.0 → 0.5.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 +6 -323
- package/agentAdapter.d.ts +26 -0
- package/auditLog.d.ts +54 -0
- package/capability.d.ts +67 -0
- package/cborCodec.d.ts +34 -0
- package/conformanceVectors.d.ts +20 -0
- package/encryption.d.ts +85 -0
- package/envelopeCbor.d.ts +33 -0
- package/frameworkAdapters.d.ts +72 -0
- package/gateway.d.ts +53 -0
- package/grpcBinding.d.ts +29 -0
- package/httpBinding.d.ts +50 -0
- package/index.d.ts +39 -0
- package/index.js +3662 -0
- package/keyInfra.d.ts +64 -0
- package/keyRegistry.d.ts +9 -0
- package/keyRotation.d.ts +20 -0
- package/mcpGateway.d.ts +37 -0
- package/mcpTransports.d.ts +62 -0
- package/mcpWrapper.d.ts +83 -0
- package/otel.d.ts +65 -0
- package/package.json +13 -79
- package/policyEnforcer.d.ts +50 -0
- package/policyTelemetryFeedback.d.ts +11 -0
- package/protocol.d.ts +66 -0
- package/protocolAgent.d.ts +58 -0
- package/protocolBinary.d.ts +8 -0
- package/protocolCapabilities.d.ts +24 -0
- package/protocolReplay.d.ts +35 -0
- package/protocolTransport.d.ts +73 -0
- package/queueBinding.d.ts +43 -0
- package/rateLimiter.d.ts +18 -0
- package/{src/redisClient.ts → redisClient.d.ts} +25 -75
- package/replayStores.d.ts +98 -0
- package/revocation.d.ts +71 -0
- package/routePolicy.d.ts +30 -0
- package/runtimePolicy.d.ts +24 -0
- package/runtimePolicyManager.d.ts +15 -0
- package/runtimePolicyPresets.d.ts +11 -0
- package/signedResponse.d.ts +21 -0
- package/stream.d.ts +59 -0
- package/telemetry.d.ts +79 -0
- package/webhookBinding.d.ts +30 -0
- package/wsBinding.d.ts +52 -0
- package/.dockerignore +0 -19
- package/.github/dependabot.yml +0 -32
- package/.github/workflows/ci.yml +0 -31
- package/.github/workflows/publish.yml +0 -59
- package/.github/workflows/scorecard.yml +0 -37
- package/7h3.example.yaml +0 -125
- package/CHANGELOG.md +0 -92
- package/CONTRIBUTING.md +0 -82
- package/Dockerfile +0 -73
- package/GOVERNANCE.md +0 -62
- package/SECURITY.md +0 -70
- package/bench-results/replay-cache-full-1777891033256.json +0 -10
- package/bench-results/replay-cache-full-1777896317488.json +0 -10
- package/bench-results/replay-cache-full-1777900993184.json +0 -10
- package/bench-results/replay-cache-full-1777901019285.json +0 -10
- package/bench-results/replay-cache-quick-1777870170126.json +0 -10
- package/bench-results/signature-profiles-quick-1775875160079.json +0 -85
- package/bench-results/signature-profiles-quick-1775983539716.json +0 -85
- package/bench-results/signature-profiles-quick-1776237913190.json +0 -85
- package/bench-results/wire-codecs-full-1777891019803.json +0 -93
- package/bench-results/wire-codecs-full-1777896260964.json +0 -93
- package/bench-results/wire-codecs-full-1777901004247.json +0 -93
- package/bench-results/wire-codecs-quick-1775972879056.json +0 -93
- package/bench-results/wire-codecs-quick-1775983541111.json +0 -93
- package/bench-results/wire-codecs-quick-1776237914299.json +0 -93
- package/bench-results/wire-codecs-quick-1777841285236.json +0 -93
- package/bench-results/wire-codecs-quick-1777841321772.json +0 -93
- package/bench-results/wire-codecs-quick-1777841330408.json +0 -93
- package/bench-results/wire-codecs-quick-1777852886082.json +0 -93
- package/bench-results/wire-codecs-quick-1777852988773.json +0 -93
- package/bench-results/wire-codecs-quick-1777870188095.json +0 -93
- package/bench-results/wire-codecs-quick-1777870263918.json +0 -93
- package/bench-results/wire-codecs-quick-1777870455034.json +0 -93
- package/bench-results/wire-codecs-quick-1778816163081.json +0 -93
- package/bench-results/wire-codecs-quick-1778843936130.json +0 -93
- package/bin/7h3.ts +0 -385
- package/conformance/7h3_v0_1.json +0 -77
- package/conformance/7h3_v0_1_binary.json +0 -20
- package/conformance/aip_v0_1_binary.json +0 -20
- package/docker-compose.yaml +0 -77
- package/docs/ADOPTION_PLAN.md +0 -120
- package/docs/AGENTS.md +0 -77
- package/docs/AIP_RFC_v0.1.md +0 -97
- package/docs/AI_DECISION_CARD.md +0 -122
- package/docs/AI_RUNTIME_POLICY.json +0 -126
- package/docs/AI_RUNTIME_POLICY.yaml +0 -110
- package/docs/BACKPRESSURE_TUNING.md +0 -65
- package/docs/BENCHMARK_CLAIM_MATRIX.md +0 -42
- package/docs/BENCHMARK_REPORT_TEMPLATE.md +0 -169
- package/docs/BINARY_CODEC_BENCH.md +0 -23
- package/docs/CLEAN_CLONE_RUNBOOK.md +0 -36
- package/docs/CLOCK_SKEW_POLICY.md +0 -30
- package/docs/DISTRIBUTED_REPLAY.md +0 -142
- package/docs/FUZZ_CAMPAIGN.md +0 -121
- package/docs/GATEWAY.md +0 -195
- package/docs/KEY_MANAGEMENT_POLICY.md +0 -53
- package/docs/KEY_REVOCATION.md +0 -69
- package/docs/MCP_WRAPPER.md +0 -159
- package/docs/MIGRATION_GUIDE.md +0 -40
- package/docs/OPERATORS.md +0 -184
- package/docs/PERF_REGRESSION_POLICY.md +0 -34
- package/docs/PROJECT_EXAMINATION_2026-05-31.md +0 -219
- package/docs/RELEASE_BENCHMARK_REPORT_2026-05-15.md +0 -135
- package/docs/RELEASE_GATE.md +0 -25
- package/docs/RELEASE_NOTES_v0.1.0.md +0 -54
- package/docs/SECURITY_REVIEW_2026-06-05.md +0 -165
- package/docs/TELEMETRY.md +0 -41
- package/docs/THREAT_MODEL.md +0 -89
- package/docs/VERSIONING_POLICY.md +0 -30
- package/docs/assets/banner.png +0 -0
- package/eslint.config.js +0 -15
- package/fuzz/ts/harness-decode.ts +0 -136
- package/fuzz/ts/harness-verify.ts +0 -121
- package/fuzz/ts/run.ts +0 -35
- package/mcp-server/README.md +0 -38
- package/mcp-server/package-lock.json +0 -1187
- package/mcp-server/package.json +0 -35
- package/mcp-server/src/index.ts +0 -236
- package/mcp-server/tsconfig.json +0 -14
- package/scripts/aip-framework-quickstart.ts +0 -110
- package/scripts/aip-mcp-gateway.ts +0 -38
- package/scripts/aip-mcp-wrap-demo.ts +0 -72
- package/scripts/aip-quickstart.ts +0 -60
- package/scripts/bench-diff.ts +0 -118
- package/scripts/bench-protocol-e2e.ts +0 -937
- package/scripts/bench-protocol-openloop.ts +0 -1397
- package/scripts/bench-replay-cache.ts +0 -76
- package/scripts/bench-signature-profiles.ts +0 -180
- package/scripts/bench-wire-codecs.ts +0 -161
- package/scripts/build-binary-conformance.ts +0 -36
- package/scripts/build-release-dashboard.ts +0 -175
- package/scripts/canary-rollout.ts +0 -38
- package/scripts/mcpGatewayCli.test.ts +0 -116
- package/scripts/prepare-aip-package.ts +0 -88
- package/scripts/regen-conformance-sigs.ts +0 -18
- package/scripts/release-gate.ts +0 -19
- package/scripts/validate-runtime-policy.ts +0 -18
- package/sdk/browser/index.test.ts +0 -162
- package/sdk/browser/index.ts +0 -257
- package/sdk/browser/package.json +0 -13
- package/sdk/go/go.mod +0 -3
- package/sdk/go/http.go +0 -135
- package/sdk/go/protocol.go +0 -324
- package/sdk/go/protocol_test.go +0 -334
- package/sdk/go/webhook.go +0 -136
- package/sdk/python/README.md +0 -18
- package/sdk/python/protocol_7h3/__init__.py +0 -46
- package/sdk/python/protocol_7h3/http.py +0 -212
- package/sdk/python/protocol_7h3/keys.py +0 -149
- package/sdk/python/protocol_7h3/protocol.py +0 -525
- package/sdk/python/protocol_7h3/queue.py +0 -118
- package/sdk/python/protocol_7h3/webhook.py +0 -116
- package/sdk/python/pyproject.toml +0 -40
- package/sdk/python/tests/test_conformance.py +0 -110
- package/sdk/python/tests/test_http.py +0 -305
- package/sdk/python/tests/test_keys.py +0 -417
- package/sdk/python/tests/test_queue.py +0 -120
- package/sdk/python/tests/test_webhook.py +0 -345
- package/sdk/rust/Cargo.lock +0 -371
- package/sdk/rust/Cargo.toml +0 -25
- package/sdk/rust/README.md +0 -31
- package/sdk/rust/fuzz/Cargo.toml +0 -29
- package/sdk/rust/fuzz/fuzz_targets/fuzz_canonicalize.rs +0 -46
- package/sdk/rust/fuzz/fuzz_targets/fuzz_decode.rs +0 -11
- package/sdk/rust/src/bin/aip_mcp_gateway.rs +0 -59
- package/sdk/rust/src/http.rs +0 -145
- package/sdk/rust/src/keys.rs +0 -161
- package/sdk/rust/src/lib.rs +0 -688
- package/sdk/rust/src/queue.rs +0 -79
- package/sdk/rust/src/webhook.rs +0 -86
- package/sdk/rust/tests/conformance.rs +0 -148
- package/sdk/rust/tests/gateway.rs +0 -130
- package/sdk/rust/tests/http_webhook_queue.rs +0 -201
- package/sdk/rust/tests/keys.rs +0 -189
- package/src/agentAdapter.test.ts +0 -48
- package/src/agentAdapter.ts +0 -56
- package/src/auditLog.test.ts +0 -145
- package/src/auditLog.ts +0 -147
- package/src/conformance.test.ts +0 -136
- package/src/conformanceVectors.ts +0 -99
- package/src/frameworkAdapters.test.ts +0 -290
- package/src/frameworkAdapters.ts +0 -261
- package/src/gateway.test.ts +0 -343
- package/src/gateway.ts +0 -171
- package/src/grpcBinding.test.ts +0 -211
- package/src/grpcBinding.ts +0 -103
- package/src/httpBinding.test.ts +0 -376
- package/src/httpBinding.ts +0 -163
- package/src/index.ts +0 -32
- package/src/keyInfra.test.ts +0 -278
- package/src/keyInfra.ts +0 -228
- package/src/keyRegistry.ts +0 -59
- package/src/keyRotation.test.ts +0 -78
- package/src/keyRotation.ts +0 -72
- package/src/mcpGateway.test.ts +0 -129
- package/src/mcpGateway.ts +0 -250
- package/src/mcpTransports.test.ts +0 -92
- package/src/mcpTransports.ts +0 -169
- package/src/mcpWrapper.test.ts +0 -179
- package/src/mcpWrapper.ts +0 -206
- package/src/policyEnforcer.test.ts +0 -99
- package/src/policyEnforcer.ts +0 -169
- package/src/policyTelemetryFeedback.test.ts +0 -25
- package/src/policyTelemetryFeedback.ts +0 -38
- package/src/protocol.bench.ts +0 -37
- package/src/protocol.test.ts +0 -155
- package/src/protocol.ts +0 -413
- package/src/protocolAgent.test.ts +0 -105
- package/src/protocolAgent.ts +0 -169
- package/src/protocolBinary.test.ts +0 -165
- package/src/protocolBinary.ts +0 -312
- package/src/protocolCapabilities.ts +0 -70
- package/src/protocolFuzz.advanced.test.ts +0 -235
- package/src/protocolFuzz.test.ts +0 -111
- package/src/protocolNegative.test.ts +0 -97
- package/src/protocolReplay.test.ts +0 -71
- package/src/protocolReplay.ts +0 -194
- package/src/protocolTransport.test.ts +0 -556
- package/src/protocolTransport.ts +0 -483
- package/src/queueBinding.test.ts +0 -130
- package/src/queueBinding.ts +0 -102
- package/src/rateLimiter.test.ts +0 -96
- package/src/rateLimiter.ts +0 -46
- package/src/redisIntegration.test.ts +0 -134
- package/src/replayStores.test.ts +0 -141
- package/src/replayStores.ts +0 -82
- package/src/revocation.test.ts +0 -98
- package/src/revocation.ts +0 -0
- package/src/routePolicy.test.ts +0 -87
- package/src/routePolicy.ts +0 -72
- package/src/runtimePolicy.test.ts +0 -49
- package/src/runtimePolicy.ts +0 -81
- package/src/runtimePolicyManager.test.ts +0 -29
- package/src/runtimePolicyManager.ts +0 -50
- package/src/runtimePolicyPresets.ts +0 -43
- package/src/signedResponse.test.ts +0 -111
- package/src/signedResponse.ts +0 -83
- package/src/webhookBinding.test.ts +0 -144
- package/src/webhookBinding.ts +0 -115
- package/src/wsBinding.test.ts +0 -221
- package/src/wsBinding.ts +0 -100
- package/tsconfig.json +0 -15
- package/tsconfig.lib.json +0 -23
- package/vite.lib.config.ts +0 -16
package/README.md
CHANGED
|
@@ -1,333 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
<img src="./docs/assets/banner.png" alt="@7h3/protocol — AIP: Sign every message. Reject every replay." width="100%">
|
|
1
|
+
# @7h3/protocol
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
7h3 Protocol (wire version `7h3/0.1`):
|
|
4
|
+
deterministic, signed, replay-safe AI-to-AI message envelopes.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
[](https://www.npmjs.com/package/@7h3/protocol-mcp)
|
|
8
|
-
[](https://pypi.org/project/aip7h3/)
|
|
9
|
-
[](https://crates.io/crates/aip7h3)
|
|
10
|
-
[](https://github.com/IceMasterT/7h3-protocol-aip/tree/main/src)
|
|
11
|
-
[](./package.json)
|
|
12
|
-
[](./tsconfig.json)
|
|
13
|
-
[](./LICENSE)
|
|
14
|
-
[](./docs/VERSIONING_POLICY.md)
|
|
15
|
-
|
|
16
|
-
<br/>
|
|
17
|
-
|
|
18
|
-
**The signing-and-replay layer your agent protocol forgot.**
|
|
19
|
-
|
|
20
|
-
<br/>
|
|
21
|
-
</div>
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## Why it exists
|
|
26
|
-
|
|
27
|
-
The dominant agent protocols ship messages unsigned:
|
|
28
|
-
|
|
29
|
-
- **MCP** uses plain JSON-RPC 2.0 — no signatures, no replay protection. Parameters can be altered in transit; valid messages can be replayed indefinitely.
|
|
30
|
-
- **A2A** signs *Agent Cards* for domain identity — but not the per-message task traffic.
|
|
31
|
-
|
|
32
|
-
AIP fills exactly that gap. It is a hardening envelope you put *around* MCP or A2A traffic — not a competitor to them. Every message gets signed, TTL-bounded, and replay-checked before it reaches your handler.
|
|
33
|
-
|
|
34
|
-
Use it when agents trigger real side effects (writes, payments, tool calls) and you need tamper-evidence, replay-safety, and auditability.
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## Guarantees
|
|
39
|
-
|
|
40
|
-
| Property | Mechanism |
|
|
41
|
-
|---|---|
|
|
42
|
-
| **Authentic** | HMAC-SHA256 (HS256) or Ed25519 over a canonical payload — real WebCrypto, no hand-rolled crypto |
|
|
43
|
-
| **Deterministic** | Fixed-key-order canonicalization; signatures match byte-for-byte across TS / Python / Rust |
|
|
44
|
-
| **Replay-resistant** | `(sender, messageId, nonce)` uniqueness window + TTL / clock-skew enforcement |
|
|
45
|
-
| **Polyglot** | Shared conformance fixture set (`conformance/aip_v0_1.json`) proves parity across all three runtimes |
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## Install
|
|
6
|
+
Install:
|
|
50
7
|
|
|
51
8
|
```bash
|
|
52
9
|
npm install @7h3/protocol
|
|
53
10
|
```
|
|
54
11
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
### MCP server (for Claude Code / Claude Desktop)
|
|
58
|
-
|
|
59
|
-
The companion `@7h3/protocol-mcp` package installs five tools into your AI assistant for generating secrets, keypairs, and boilerplate.
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
# Claude Code
|
|
63
|
-
claude mcp add aip -- npx @7h3/protocol-mcp
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
```json
|
|
67
|
-
// Claude Desktop — claude_desktop_config.json
|
|
68
|
-
{
|
|
69
|
-
"mcpServers": {
|
|
70
|
-
"aip": { "command": "npx", "args": ["@7h3/protocol-mcp"] }
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
| Tool | What it does |
|
|
76
|
-
|---|---|
|
|
77
|
-
| `aip_generate_secret` | 32-byte HMAC secret → `AIP_SECRET` |
|
|
78
|
-
| `aip_generate_keypair` | Ed25519 keypair → env vars |
|
|
79
|
-
| `aip_wrap_mcp_server` | Ready-to-paste boilerplate for your MCP server |
|
|
80
|
-
| `aip_sign` | Sign a test envelope (debugging / fixture generation) |
|
|
81
|
-
| `aip_verify` | Verify an envelope's signature and shape |
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## Quick start
|
|
86
|
-
|
|
87
|
-
### HMAC (shared secret — simplest path)
|
|
12
|
+
Import:
|
|
88
13
|
|
|
89
14
|
```ts
|
|
90
|
-
import {
|
|
91
|
-
createEnvelope, signEnvelopeHmac, verifyEnvelopeHmac, validateEnvelope,
|
|
92
|
-
} from '@7h3/protocol'
|
|
93
|
-
|
|
94
|
-
const secret = 'shared-secret'
|
|
95
|
-
const envelope = await signEnvelopeHmac(
|
|
96
|
-
createEnvelope({ sender: 'planner', recipient: 'worker', intent: 'TASK', content: 'do-the-thing' }),
|
|
97
|
-
secret,
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
const diagnostics = validateEnvelope(envelope) // shape / TTL / version checks
|
|
101
|
-
const ok = await verifyEnvelopeHmac(envelope, secret) // tamper + auth check
|
|
102
|
-
// → replay-check downstream via your transport's replay cache
|
|
15
|
+
import { createAipAgentAdapter, receiveEnvelope } from '@7h3/protocol'
|
|
103
16
|
```
|
|
104
|
-
|
|
105
|
-
### Ed25519 (asymmetric — production recommendation)
|
|
106
|
-
|
|
107
|
-
> **Why Ed25519?** HMAC is a shared secret — any peer that can verify can also forge. Ed25519 is asymmetric: you sign with a private key, peers verify with your public key only. Compromising a peer does not compromise your signing key.
|
|
108
|
-
|
|
109
|
-
```ts
|
|
110
|
-
import {
|
|
111
|
-
generateEd25519KeypairBase64Url, createEnvelope,
|
|
112
|
-
signEnvelopeEd25519, verifyEnvelopeEd25519,
|
|
113
|
-
} from '@7h3/protocol'
|
|
114
|
-
|
|
115
|
-
const { privateKey, publicKey } = await generateEd25519KeypairBase64Url()
|
|
116
|
-
const envelope = await signEnvelopeEd25519(
|
|
117
|
-
createEnvelope({ sender: 'planner', recipient: 'worker', intent: 'TASK', content: 'do-the-thing' }),
|
|
118
|
-
privateKey, 'k1',
|
|
119
|
-
)
|
|
120
|
-
const ok = await verifyEnvelopeEd25519(envelope, publicKey)
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## MCP hardening wrapper
|
|
126
|
-
|
|
127
|
-
Wrap any existing MCP server or client — handler signature does not change:
|
|
128
|
-
|
|
129
|
-
```ts
|
|
130
|
-
import { wrapMcpServer, wrapMcpClient, signEnvelopeEd25519 } from '@7h3/protocol'
|
|
131
|
-
|
|
132
|
-
// Server side
|
|
133
|
-
const secureServer = wrapMcpServer(myMcpHandler, {
|
|
134
|
-
selfAgentId: 'my-server',
|
|
135
|
-
sign: (e) => signEnvelopeEd25519(e, serverPrivateKey, 'k1'),
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
// Client side
|
|
139
|
-
const { send } = wrapMcpClient({
|
|
140
|
-
selfAgentId: 'my-client',
|
|
141
|
-
peerAgentId: 'my-server',
|
|
142
|
-
sign: (e) => signEnvelopeEd25519(e, clientPrivateKey, 'k1'),
|
|
143
|
-
receive: { signatureResolver: async ({ keyId }) => ({ alg: 'ED25519', publicKey: serverPublicKey }) },
|
|
144
|
-
})
|
|
145
|
-
const response = await send({ jsonrpc: '2.0', id: 1, method: 'tools/list' }, fetch)
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
The wrapper enforces four bindings beyond signature verification:
|
|
149
|
-
|
|
150
|
-
| Binding | Attack defeated |
|
|
151
|
-
|---|---|
|
|
152
|
-
| **Recipient** | Server rejects envelopes not addressed to `selfAgentId` — cross-server relay |
|
|
153
|
-
| **Sender** | Client accepts responses only from `peerAgentId` — response spoofing |
|
|
154
|
-
| **Correlation** | Client enforces `correlationId === request messageId` — response substitution |
|
|
155
|
-
| **Replay** | `InMemoryReplayCache` injected by default — replay of prior requests |
|
|
156
|
-
|
|
157
|
-
Demo: `npm run aip:mcp:wrap`
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
## Wire formats
|
|
162
|
-
|
|
163
|
-
Three formats — choose by context:
|
|
164
|
-
|
|
165
|
-
| Format | Use case |
|
|
166
|
-
|---|---|
|
|
167
|
-
| `json` | Human-readable, debug-friendly |
|
|
168
|
-
| `compact` | Minified JSON — smaller over HTTP |
|
|
169
|
-
| `binary` | MessagePack (magic `AIPB`) — highest throughput, lowest parse overhead |
|
|
170
|
-
|
|
171
|
-
```ts
|
|
172
|
-
import { encodeEnvelope, decodeEnvelope } from '@7h3/protocol'
|
|
173
|
-
|
|
174
|
-
const wire = encodeEnvelope(envelope, 'binary') // Uint8Array
|
|
175
|
-
const back = decodeEnvelope(wire) // ProtocolEnvelope
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## Distributed replay store (Redis)
|
|
181
|
-
|
|
182
|
-
Production deployments need a shared replay store across agent instances:
|
|
183
|
-
|
|
184
|
-
```ts
|
|
185
|
-
import { createRedisReplayStore, DistributedReplayCache } from '@7h3/protocol'
|
|
186
|
-
|
|
187
|
-
const store = createRedisReplayStore(redisClient, {
|
|
188
|
-
errorBehavior: 'fallback', // degrade to local store on Redis outage — never silent
|
|
189
|
-
onDegraded: (err) => telemetry.error('replay-store-degraded', err),
|
|
190
|
-
})
|
|
191
|
-
const replayCache = new DistributedReplayCache(store)
|
|
192
|
-
|
|
193
|
-
// Pass replayCache into receiveEnvelope or wrapMcpServer/wrapMcpClient
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
- Atomic `SET NX PX` reserve — no double-processing under concurrent writes
|
|
197
|
-
- `reserveMany` batch pipeline — low overhead for high-volume handlers
|
|
198
|
-
- `errorBehavior: 'fallback' | 'reject' | 'allow'` — operator controls degradation posture
|
|
199
|
-
- See `docs/DISTRIBUTED_REPLAY.md`
|
|
200
|
-
|
|
201
|
-
---
|
|
202
|
-
|
|
203
|
-
## Fleet-wide key revocation
|
|
204
|
-
|
|
205
|
-
```ts
|
|
206
|
-
import { createRedisRevocationStore, withRevocationCheck } from '@7h3/protocol'
|
|
207
|
-
|
|
208
|
-
const revocationStore = createRedisRevocationStore(redisClient) // fail-closed default
|
|
209
|
-
const secureResolver = withRevocationCheck(mySignatureResolver, revocationStore)
|
|
210
|
-
// Revoked key → resolver returns undefined → verification fails
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
- Cached reads (5 s TTL by default) — low overhead on the verify hot path
|
|
214
|
-
- Fail-closed default: Redis outage → reject, not allow
|
|
215
|
-
- See `docs/KEY_REVOCATION.md`
|
|
216
|
-
|
|
217
|
-
---
|
|
218
|
-
|
|
219
|
-
## Transport adapters
|
|
220
|
-
|
|
221
|
-
Zero new runtime dependencies — only Node built-ins and global `fetch`:
|
|
222
|
-
|
|
223
|
-
```ts
|
|
224
|
-
import { serveMcpOverStdio, createStdioMcpClient } from '@7h3/protocol'
|
|
225
|
-
import { createHttpMcpHandler, createHttpMcpClient } from '@7h3/protocol'
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
| Adapter | Notes |
|
|
229
|
-
|---|---|
|
|
230
|
-
| `serveMcpOverStdio` + `createStdioMcpClient` | Newline-delimited; in-order sequential chain prevents response interleaving |
|
|
231
|
-
| `createHttpMcpHandler` + `createHttpMcpClient` | `node:http` handler + `fetch` client; supports `binary` wire format |
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
## Framework adapters
|
|
236
|
-
|
|
237
|
-
LangChain, LlamaIndex, and JSON-RPC bridge adapters wrap `AipAgentAdapter` to translate between AIP envelopes and framework-native message types:
|
|
238
|
-
|
|
239
|
-
```ts
|
|
240
|
-
import { LangChainAipAdapter, LlamaIndexAipAdapter, JsonRpcBridge } from '@7h3/protocol'
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
---
|
|
244
|
-
|
|
245
|
-
## Policy and telemetry
|
|
246
|
-
|
|
247
|
-
Runtime policy controls transport behavior, retry, rate limits, and safety invariants — loaded from `AI_RUNTIME_POLICY.yaml` or inline:
|
|
248
|
-
|
|
249
|
-
```ts
|
|
250
|
-
import { loadRuntimePolicy, validateRuntimePolicy, PolicyEnforcer } from '@7h3/protocol'
|
|
251
|
-
|
|
252
|
-
const policy = await loadRuntimePolicy({ path: './AI_RUNTIME_POLICY.yaml' })
|
|
253
|
-
const enforcer = new PolicyEnforcer(policy)
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
See `docs/TELEMETRY.md`, `docs/AI_DECISION_CARD.md`, `docs/OPERATORS.md`.
|
|
257
|
-
|
|
258
|
-
---
|
|
259
|
-
|
|
260
|
-
## Polyglot parity
|
|
261
|
-
|
|
262
|
-
All three SDKs are driven by the same conformance fixture set at `conformance/aip_v0_1.json`. Signatures verified against known vectors in all three runtimes:
|
|
263
|
-
|
|
264
|
-
```bash
|
|
265
|
-
npm test # TypeScript (131 tests / 23 files)
|
|
266
|
-
npm run conformance:python # Python unittest
|
|
267
|
-
npm run conformance:rust # Rust cargo test (7 tests)
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
---
|
|
271
|
-
|
|
272
|
-
## Status
|
|
273
|
-
|
|
274
|
-
**Version: 0.1.2** · Wire protocol: `aip/0.1`
|
|
275
|
-
|
|
276
|
-
| What | Status |
|
|
277
|
-
|---|---|
|
|
278
|
-
| Core test suite | ✅ 131 tests / 23 files — all green |
|
|
279
|
-
| Cryptography | ✅ Real WebCrypto — HMAC-SHA256 + Ed25519 (no hand-rolled crypto) |
|
|
280
|
-
| Deterministic canonicalization | ✅ Fixed key order; byte-identical across runtimes |
|
|
281
|
-
| TS/Python/Rust parity | ✅ Shared conformance fixtures; all pass |
|
|
282
|
-
| Distributed replay (Redis) | ✅ Atomic `SET NX PX`; batch pipeline; graceful degradation |
|
|
283
|
-
| Fleet-wide revocation (Redis) | ✅ Fail-closed; cached reads; stale-serve during outage |
|
|
284
|
-
| MCP hardening wrapper | ✅ 4 bindings; all independently tested |
|
|
285
|
-
| Property-based fuzz tests | ✅ 8 properties via fast-check (wire decoder, canonicalization, replay) |
|
|
286
|
-
| Live-Redis integration test | ✅ Auto-skips if no server present — no false passes |
|
|
287
|
-
| Formal fuzz campaign | ✅ TypeScript mutation harnesses run clean (50k/20k rounds, 0 crashes); Rust targets built and run (4.9M iterations, no panics in `canonicalize_envelope`/`decode_envelope`) — see [`docs/FUZZ_CAMPAIGN.md`](./docs/FUZZ_CAMPAIGN.md) |
|
|
288
|
-
| Independent security audit | ⚠️ Not yet performed by an external reviewer — internal AI-assisted review completed 2026-06-05, 2 bugs found and fixed (see [`docs/SECURITY_REVIEW_2026-06-05.md`](./docs/SECURITY_REVIEW_2026-06-05.md)); cryptographic primitives are standard WebCrypto; parsing/replay/canonicalization logic remains unaudited by a qualified third party |
|
|
289
|
-
| Python Ed25519 | ✅ Pure-Python fallback — no external packages required; tries `cryptography` → `PyNaCl` → pure Python in order |
|
|
290
|
-
| Rust crates.io publish | ✅ Metadata complete; `cargo publish --dry-run` passes — publish with `cargo publish` when ready |
|
|
291
|
-
| Redis HA | ✅ Sentinel, Cluster, and Upstash adapter patterns documented in [`docs/DISTRIBUTED_REPLAY.md`](./docs/DISTRIBUTED_REPLAY.md) |
|
|
292
|
-
|
|
293
|
-
---
|
|
294
|
-
|
|
295
|
-
## Docs
|
|
296
|
-
|
|
297
|
-
| Document | Contents |
|
|
298
|
-
|---|---|
|
|
299
|
-
| [`docs/THREAT_MODEL.md`](./docs/THREAT_MODEL.md) | Full threat coverage matrix |
|
|
300
|
-
| [`docs/MCP_WRAPPER.md`](./docs/MCP_WRAPPER.md) | MCP wrapper usage, transport examples, HMAC vs Ed25519 comparison |
|
|
301
|
-
| [`docs/DISTRIBUTED_REPLAY.md`](./docs/DISTRIBUTED_REPLAY.md) | Redis store setup, `errorBehavior` table, ops guidance |
|
|
302
|
-
| [`docs/KEY_REVOCATION.md`](./docs/KEY_REVOCATION.md) | Revocation store setup, cache TTL tuning |
|
|
303
|
-
| [`docs/KEY_MANAGEMENT_POLICY.md`](./docs/KEY_MANAGEMENT_POLICY.md) | Key lifecycle and rotation policy |
|
|
304
|
-
| [`docs/CLOCK_SKEW_POLICY.md`](./docs/CLOCK_SKEW_POLICY.md) | Clock sync requirements |
|
|
305
|
-
| [`docs/VERSIONING_POLICY.md`](./docs/VERSIONING_POLICY.md) | Wire freeze guarantees, semver policy |
|
|
306
|
-
| [`docs/MIGRATION_GUIDE.md`](./docs/MIGRATION_GUIDE.md) | Breaking-change upgrade paths |
|
|
307
|
-
| [`docs/OPERATORS.md`](./docs/OPERATORS.md) | Deployment and operations reference |
|
|
308
|
-
| [`docs/TELEMETRY.md`](./docs/TELEMETRY.md) | Telemetry hooks and observability |
|
|
309
|
-
| [`docs/SECURITY_REVIEW_2026-06-05.md`](./docs/SECURITY_REVIEW_2026-06-05.md) | AI-assisted internal security review — findings, fixes, positive findings |
|
|
310
|
-
| [`docs/PROJECT_EXAMINATION_2026-05-31.md`](./docs/PROJECT_EXAMINATION_2026-05-31.md) | Independent examination — verified vs asserted |
|
|
311
|
-
| [`CHANGELOG.md`](./CHANGELOG.md) | Full version history |
|
|
312
|
-
|
|
313
|
-
---
|
|
314
|
-
|
|
315
|
-
## Security
|
|
316
|
-
|
|
317
|
-
Report vulnerabilities via the coordinated disclosure process in [`SECURITY.md`](./SECURITY.md). **Do not open a public issue for security findings.** 48-hour acknowledgement SLA; 14-day critical patch SLA.
|
|
318
|
-
|
|
319
|
-
The cryptographic primitives are standard (WebCrypto Ed25519 / HMAC-SHA256). The envelope parsing, canonicalization, and replay-cache logic have not been formally audited. No independent security audit has been performed. Treat accordingly in high-stakes deployments.
|
|
320
|
-
|
|
321
|
-
---
|
|
322
|
-
|
|
323
|
-
## Contributing
|
|
324
|
-
|
|
325
|
-
See [`CONTRIBUTING.md`](./CONTRIBUTING.md) — test commands, wire-freeze policy, conformance fixture update requirement, and PR workflow.
|
|
326
|
-
|
|
327
|
-
## Governance
|
|
328
|
-
|
|
329
|
-
See [`GOVERNANCE.md`](./GOVERNANCE.md) — single-maintainer stage, decision process, co-maintainership path (LF Minimum Viable Governance style).
|
|
330
|
-
|
|
331
|
-
## License
|
|
332
|
-
|
|
333
|
-
MIT
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type AgentReceiveResult, type AgentSessionConfig } from './protocolAgent';
|
|
2
|
+
import { type IntentKind, type ProtocolEnvelope } from './protocol';
|
|
3
|
+
import { type WireEnvelope, type WireFormat } from './protocolTransport';
|
|
4
|
+
export interface AipAdapterConfig extends AgentSessionConfig {
|
|
5
|
+
wireFormat?: WireFormat;
|
|
6
|
+
}
|
|
7
|
+
export declare class AipAgentAdapter {
|
|
8
|
+
private readonly session;
|
|
9
|
+
private readonly wireFormat;
|
|
10
|
+
constructor(config: AipAdapterConfig);
|
|
11
|
+
toRaw(envelope: ProtocolEnvelope): WireEnvelope;
|
|
12
|
+
createRawIntent(input: {
|
|
13
|
+
recipient?: string;
|
|
14
|
+
intent: IntentKind;
|
|
15
|
+
content: string;
|
|
16
|
+
capability?: string;
|
|
17
|
+
correlationId?: string;
|
|
18
|
+
ttlMs?: number;
|
|
19
|
+
messageId?: string;
|
|
20
|
+
nonce?: string;
|
|
21
|
+
nowMs?: number;
|
|
22
|
+
}): Promise<WireEnvelope>;
|
|
23
|
+
receiveRaw(raw: WireEnvelope, nowMs?: number): Promise<AgentReceiveResult>;
|
|
24
|
+
handleRaw(raw: WireEnvelope, emitResponseRaw: (rawResponse: WireEnvelope, responseEnvelope: ProtocolEnvelope) => void | Promise<void>, nowMs?: number): Promise<AgentReceiveResult>;
|
|
25
|
+
}
|
|
26
|
+
export declare function createAipAgentAdapter(config: AipAdapterConfig): AipAgentAdapter;
|
package/auditLog.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type AuditEventType = 'verify-ok' | 'verify-fail' | 'rate-limited' | 'sender-denied' | 'response-signed';
|
|
2
|
+
export interface AuditEntry {
|
|
3
|
+
id: string;
|
|
4
|
+
timestampMs: number;
|
|
5
|
+
type: AuditEventType;
|
|
6
|
+
sender?: string;
|
|
7
|
+
path?: string;
|
|
8
|
+
method?: string;
|
|
9
|
+
envelopeId?: string;
|
|
10
|
+
failReason?: string;
|
|
11
|
+
upstream?: string;
|
|
12
|
+
responseStatus?: number;
|
|
13
|
+
entrySignature: string;
|
|
14
|
+
}
|
|
15
|
+
export interface AuditLogger {
|
|
16
|
+
log(event: Omit<AuditEntry, 'id' | 'timestampMs' | 'entrySignature'>): Promise<void>;
|
|
17
|
+
query(opts?: {
|
|
18
|
+
type?: AuditEventType;
|
|
19
|
+
sender?: string;
|
|
20
|
+
since?: number;
|
|
21
|
+
limit?: number;
|
|
22
|
+
}): Promise<AuditEntry[]>;
|
|
23
|
+
verify(entry: AuditEntry, publicKey: string): Promise<boolean>;
|
|
24
|
+
}
|
|
25
|
+
declare class InMemoryAuditLog implements AuditLogger {
|
|
26
|
+
private entries;
|
|
27
|
+
private privateKey;
|
|
28
|
+
private maxEntries;
|
|
29
|
+
constructor(privateKey: string, maxEntries?: number);
|
|
30
|
+
log(event: Omit<AuditEntry, 'id' | 'timestampMs' | 'entrySignature'>): Promise<void>;
|
|
31
|
+
query(opts?: {
|
|
32
|
+
type?: AuditEventType;
|
|
33
|
+
sender?: string;
|
|
34
|
+
since?: number;
|
|
35
|
+
limit?: number;
|
|
36
|
+
}): Promise<AuditEntry[]>;
|
|
37
|
+
verify(entry: AuditEntry, publicKey: string): Promise<boolean>;
|
|
38
|
+
size(): number;
|
|
39
|
+
}
|
|
40
|
+
declare class NoopAuditLog implements AuditLogger {
|
|
41
|
+
log(_event: Omit<AuditEntry, 'id' | 'timestampMs' | 'entrySignature'>): Promise<void>;
|
|
42
|
+
query(_opts?: {
|
|
43
|
+
type?: AuditEventType;
|
|
44
|
+
sender?: string;
|
|
45
|
+
since?: number;
|
|
46
|
+
limit?: number;
|
|
47
|
+
}): Promise<AuditEntry[]>;
|
|
48
|
+
verify(_entry: AuditEntry, _publicKey: string): Promise<boolean>;
|
|
49
|
+
size(): number;
|
|
50
|
+
}
|
|
51
|
+
export declare function createAuditLog(privateKey: string, opts?: {
|
|
52
|
+
maxEntries?: number;
|
|
53
|
+
}): InMemoryAuditLog;
|
|
54
|
+
export { InMemoryAuditLog, NoopAuditLog };
|
package/capability.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { generateEd25519KeypairBase64Url } from './protocol';
|
|
2
|
+
export { generateEd25519KeypairBase64Url };
|
|
3
|
+
export interface CapabilityScope {
|
|
4
|
+
pathGlob: string;
|
|
5
|
+
methods?: string[];
|
|
6
|
+
maxDelegations?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface CapabilityToken {
|
|
9
|
+
id: string;
|
|
10
|
+
version: '7h3-cap/1';
|
|
11
|
+
issuer: string;
|
|
12
|
+
subject: string;
|
|
13
|
+
scopes: CapabilityScope[];
|
|
14
|
+
issuedAt: number;
|
|
15
|
+
expiresAt: number;
|
|
16
|
+
delegationDepth: number;
|
|
17
|
+
parentTokenId?: string;
|
|
18
|
+
/** How many more times this token can be re-delegated. undefined = unlimited, 0 = no further delegation. */
|
|
19
|
+
maxDelegations: number | undefined;
|
|
20
|
+
signature: string;
|
|
21
|
+
keyId: string;
|
|
22
|
+
}
|
|
23
|
+
export type CapabilityVerifyResult = {
|
|
24
|
+
ok: true;
|
|
25
|
+
token: CapabilityToken;
|
|
26
|
+
chain: CapabilityToken[];
|
|
27
|
+
} | {
|
|
28
|
+
ok: false;
|
|
29
|
+
reason: string;
|
|
30
|
+
};
|
|
31
|
+
export declare const CAP_HEADER = "x-7h3-capability";
|
|
32
|
+
/**
|
|
33
|
+
* Deterministic canonical form for signing: alphabetically sorted top-level fields,
|
|
34
|
+
* each scope also sorted. The `signature` field is excluded.
|
|
35
|
+
*/
|
|
36
|
+
export declare function canonicalizeCapabilityToken(token: Omit<CapabilityToken, 'signature'>): string;
|
|
37
|
+
export declare function issueCapabilityToken(opts: {
|
|
38
|
+
issuerPrivateKey: string;
|
|
39
|
+
issuerId: string;
|
|
40
|
+
subject: string;
|
|
41
|
+
scopes: CapabilityScope[];
|
|
42
|
+
ttlMs: number;
|
|
43
|
+
maxDelegations?: number;
|
|
44
|
+
keyId?: string;
|
|
45
|
+
}): Promise<CapabilityToken>;
|
|
46
|
+
export declare function delegateCapabilityToken(opts: {
|
|
47
|
+
parentToken: CapabilityToken;
|
|
48
|
+
delegatorPrivateKey: string;
|
|
49
|
+
delegatorId: string;
|
|
50
|
+
newSubject: string;
|
|
51
|
+
scopes?: CapabilityScope[];
|
|
52
|
+
ttlMs: number;
|
|
53
|
+
keyId?: string;
|
|
54
|
+
}): Promise<CapabilityToken>;
|
|
55
|
+
export declare function verifyCapabilityToken(token: CapabilityToken, publicKey: string, opts?: {
|
|
56
|
+
now?: number;
|
|
57
|
+
}): Promise<boolean>;
|
|
58
|
+
export declare function verifyCapabilityChain(chain: CapabilityToken[], keyRegistry: {
|
|
59
|
+
getPublicKey(id: string): Promise<string | null>;
|
|
60
|
+
}, opts?: {
|
|
61
|
+
requiredPathGlob?: string;
|
|
62
|
+
requiredMethod?: string;
|
|
63
|
+
now?: number;
|
|
64
|
+
}): Promise<CapabilityVerifyResult>;
|
|
65
|
+
export declare function tokenMatchesScope(token: CapabilityToken, pathGlob: string, method?: string): boolean;
|
|
66
|
+
export declare function serializeCapabilityChain(chain: CapabilityToken[]): string;
|
|
67
|
+
export declare function parseCapabilityChain(serialized: string): CapabilityToken[];
|
package/cborCodec.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal deterministic CBOR encoder/decoder — zero external dependencies.
|
|
3
|
+
* Follows RFC 8949 §4.2 deterministic encoding:
|
|
4
|
+
* - Shortest-length integers
|
|
5
|
+
* - Map keys sorted by lexicographic byte order of encoded key
|
|
6
|
+
*/
|
|
7
|
+
export declare class CborEncoder {
|
|
8
|
+
private chunks;
|
|
9
|
+
encode(value: unknown): Uint8Array;
|
|
10
|
+
private _encode;
|
|
11
|
+
private _encodeNumber;
|
|
12
|
+
private _float64Header;
|
|
13
|
+
private _encodeString;
|
|
14
|
+
private _encodeByteString;
|
|
15
|
+
private _encodeArray;
|
|
16
|
+
private _encodeMapFromAnyEntries;
|
|
17
|
+
private _encodeMapFromEntries;
|
|
18
|
+
private _compareBytes;
|
|
19
|
+
private _concatPair;
|
|
20
|
+
private _encodeHead;
|
|
21
|
+
private _encodeHeadBytes;
|
|
22
|
+
private _concat;
|
|
23
|
+
}
|
|
24
|
+
export declare class CborDecoder {
|
|
25
|
+
private data;
|
|
26
|
+
private offset;
|
|
27
|
+
decode(data: Uint8Array): unknown;
|
|
28
|
+
private _decode;
|
|
29
|
+
private _decodeUint;
|
|
30
|
+
private _readByte;
|
|
31
|
+
private _readBytes;
|
|
32
|
+
}
|
|
33
|
+
export declare function encodeCbor(value: unknown): Uint8Array;
|
|
34
|
+
export declare function decodeCbor(data: Uint8Array): unknown;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ProtocolEnvelope } from './protocol';
|
|
2
|
+
export interface ConformanceVector {
|
|
3
|
+
id: string;
|
|
4
|
+
secret: string;
|
|
5
|
+
keyId: string;
|
|
6
|
+
envelope: Omit<ProtocolEnvelope, 'signature'>;
|
|
7
|
+
canonical: string;
|
|
8
|
+
signature: string;
|
|
9
|
+
}
|
|
10
|
+
export interface Ed25519ConformanceVector {
|
|
11
|
+
id: string;
|
|
12
|
+
keyId: string;
|
|
13
|
+
publicKey: string;
|
|
14
|
+
privateKey: string;
|
|
15
|
+
envelope: Omit<ProtocolEnvelope, 'signature'>;
|
|
16
|
+
canonical: string;
|
|
17
|
+
signature: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const AIP_V01_CONFORMANCE_VECTORS: ConformanceVector[];
|
|
20
|
+
export declare const AIP_V01_ED25519_CONFORMANCE_VECTORS: Ed25519ConformanceVector[];
|
package/encryption.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E Encryption for 7h3 Protocol
|
|
3
|
+
*
|
|
4
|
+
* Uses X25519 Diffie-Hellman key exchange + ChaCha20-Poly1305 AEAD.
|
|
5
|
+
* All operations via Node.js built-in `node:crypto` — zero new dependencies.
|
|
6
|
+
*
|
|
7
|
+
* Architecture:
|
|
8
|
+
* EncryptedEnvelope = SignedEnvelope where body.content is a base64url-encoded
|
|
9
|
+
* EncryptedPayload, body.intent = 'ENCRYPTED', body.capability = 'x25519-chacha20poly1305'
|
|
10
|
+
*/
|
|
11
|
+
import { type ProtocolBody, type ProtocolEnvelope } from './protocol.js';
|
|
12
|
+
export interface X25519KeyPair {
|
|
13
|
+
/** Raw 32-byte X25519 public key, base64url-encoded (no padding) */
|
|
14
|
+
publicKey: string;
|
|
15
|
+
/** Raw 32-byte X25519 private key, base64url-encoded (no padding) */
|
|
16
|
+
privateKey: string;
|
|
17
|
+
}
|
|
18
|
+
export interface EncryptedPayload {
|
|
19
|
+
/** Ephemeral X25519 public key (base64url, raw 32 bytes) */
|
|
20
|
+
ephemeralPublic: string;
|
|
21
|
+
/** ChaCha20 nonce / HKDF salt (base64url, 12 bytes) */
|
|
22
|
+
nonce: string;
|
|
23
|
+
/** Ciphertext without auth tag (base64url) */
|
|
24
|
+
ciphertext: string;
|
|
25
|
+
/** 16-byte Poly1305 auth tag (base64url) */
|
|
26
|
+
tag: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Generate a fresh X25519 keypair.
|
|
30
|
+
* Both keys are raw 32-byte values encoded as base64url (no padding).
|
|
31
|
+
*/
|
|
32
|
+
export declare function generateX25519KeyPair(): X25519KeyPair;
|
|
33
|
+
/**
|
|
34
|
+
* Perform X25519 DH + HKDF-SHA256 to derive a 32-byte ChaCha20-Poly1305 key.
|
|
35
|
+
*
|
|
36
|
+
* @param privateKeyBase64Url - raw 32-byte X25519 private key (base64url)
|
|
37
|
+
* @param peerPublicKeyBase64Url - raw 32-byte X25519 public key (base64url)
|
|
38
|
+
* @param nonce - raw 12-byte nonce (base64url); used as HKDF salt
|
|
39
|
+
* @returns 32-byte Buffer ready for use with createCipheriv/createDecipheriv
|
|
40
|
+
*/
|
|
41
|
+
export declare function deriveEncryptionKey(privateKeyBase64Url: string, peerPublicKeyBase64Url: string, nonce: string): Buffer;
|
|
42
|
+
/**
|
|
43
|
+
* Encrypt a ProtocolBody with the recipient's X25519 public key.
|
|
44
|
+
*
|
|
45
|
+
* @returns encryptedContent (base64url-encoded EncryptedPayload JSON) and ephemeralPublic
|
|
46
|
+
*/
|
|
47
|
+
export declare function encryptBody(body: ProtocolBody, recipientX25519PublicKey: string): {
|
|
48
|
+
encryptedContent: string;
|
|
49
|
+
ephemeralPublic: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Decrypt an encrypted ProtocolBody.
|
|
53
|
+
*
|
|
54
|
+
* @param encryptedContent - base64url-encoded EncryptedPayload
|
|
55
|
+
* @param recipientX25519PrivateKey - raw 32-byte X25519 private key (base64url)
|
|
56
|
+
* @returns decrypted ProtocolBody
|
|
57
|
+
* @throws if AEAD tag verification fails
|
|
58
|
+
*/
|
|
59
|
+
export declare function decryptBody(encryptedContent: string, recipientX25519PrivateKey: string): ProtocolBody;
|
|
60
|
+
/**
|
|
61
|
+
* Encrypt and sign an envelope (full pipeline).
|
|
62
|
+
*
|
|
63
|
+
* The original body is encrypted; the envelope body is replaced with:
|
|
64
|
+
* { intent: 'ENCRYPTED', content: <encrypted-payload>, capability: 'x25519-chacha20poly1305' }
|
|
65
|
+
* The modified envelope is then signed with Ed25519.
|
|
66
|
+
*/
|
|
67
|
+
export declare function sealEnvelope(envelope: Omit<ProtocolEnvelope, 'signature'>, opts: {
|
|
68
|
+
recipientX25519PublicKey: string;
|
|
69
|
+
senderEd25519PrivateKey: string;
|
|
70
|
+
}): Promise<ProtocolEnvelope>;
|
|
71
|
+
/**
|
|
72
|
+
* Verify signature and decrypt an envelope (full pipeline).
|
|
73
|
+
*
|
|
74
|
+
* Signature is verified FIRST; decryption only proceeds if valid.
|
|
75
|
+
*
|
|
76
|
+
* @returns The signed envelope (with encrypted body) and the decrypted original body
|
|
77
|
+
* @throws if Ed25519 signature invalid or AEAD tag fails
|
|
78
|
+
*/
|
|
79
|
+
export declare function openEnvelope(envelope: ProtocolEnvelope, opts: {
|
|
80
|
+
recipientX25519PrivateKey: string;
|
|
81
|
+
senderEd25519PublicKey: string;
|
|
82
|
+
}): Promise<{
|
|
83
|
+
envelope: ProtocolEnvelope;
|
|
84
|
+
body: ProtocolBody;
|
|
85
|
+
}>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Higher-level CBOR codec for ProtocolEnvelope.
|
|
3
|
+
* Uses numeric field keys for maximum compactness.
|
|
4
|
+
*
|
|
5
|
+
* Envelope map structure:
|
|
6
|
+
* 1 → header map
|
|
7
|
+
* 2 → body map
|
|
8
|
+
* 3 → signature map (omitted if no signature)
|
|
9
|
+
*
|
|
10
|
+
* Header map:
|
|
11
|
+
* 1 → version (string)
|
|
12
|
+
* 2 → messageId (string)
|
|
13
|
+
* 3 → timestampMs (int)
|
|
14
|
+
* 4 → ttlMs (int)
|
|
15
|
+
* 5 → sender (string)
|
|
16
|
+
* 6 → recipient (string, omit if absent)
|
|
17
|
+
* 7 → nonce (string)
|
|
18
|
+
*
|
|
19
|
+
* Body map:
|
|
20
|
+
* 1 → intent (string)
|
|
21
|
+
* 2 → content (string)
|
|
22
|
+
* 3 → capability (string, omit if absent)
|
|
23
|
+
* 4 → correlationId (string, omit if absent)
|
|
24
|
+
*
|
|
25
|
+
* Signature map:
|
|
26
|
+
* 1 → alg (string)
|
|
27
|
+
* 2 → keyId (string)
|
|
28
|
+
* 3 → value (string — base64url signature)
|
|
29
|
+
*/
|
|
30
|
+
import type { ProtocolEnvelope } from './protocol';
|
|
31
|
+
export declare const CBOR_CONTENT_TYPE = "application/7h3-cbor";
|
|
32
|
+
export declare function encodeEnvelopeCbor(env: ProtocolEnvelope): Uint8Array;
|
|
33
|
+
export declare function decodeEnvelopeCbor(data: Uint8Array): ProtocolEnvelope;
|