@7h3/protocol 0.5.0 → 0.5.2
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 -1317
- 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 +3670 -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 -121
- package/policyEnforcer.d.ts +50 -0
- package/policyTelemetryFeedback.d.ts +11 -0
- package/{src/protocol.d.ts → protocol.d.ts} +6 -2
- 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 -152
- 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 -406
- 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-github.png +0 -0
- package/docs/assets/banner.png +0 -0
- package/docs/assets/banner.svg +0 -123
- 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/cbor.go +0 -551
- package/sdk/go/cbor_test.go +0 -232
- package/sdk/go/encryption.go +0 -280
- package/sdk/go/encryption_test.go +0 -318
- package/sdk/go/go.mod +0 -7
- package/sdk/go/go.sum +0 -4
- 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/replay.go +0 -121
- package/sdk/go/replay_test.go +0 -149
- package/sdk/go/webhook.go +0 -136
- package/sdk/pq/package-lock.json +0 -1358
- package/sdk/pq/package.json +0 -42
- package/sdk/pq/src/index.test.ts +0 -143
- package/sdk/pq/src/index.ts +0 -166
- package/sdk/pq/tsconfig.json +0 -14
- package/sdk/pq/vitest.config.ts +0 -7
- package/sdk/python/README.md +0 -18
- package/sdk/python/protocol_7h3/__init__.py +0 -46
- package/sdk/python/protocol_7h3/encryption.py +0 -252
- package/sdk/python/protocol_7h3/http.py +0 -212
- package/sdk/python/protocol_7h3/keys.py +0 -149
- package/sdk/python/protocol_7h3/pq.py +0 -244
- package/sdk/python/protocol_7h3/protocol.py +0 -525
- package/sdk/python/protocol_7h3/queue.py +0 -118
- package/sdk/python/protocol_7h3/replay.py +0 -98
- 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_encryption.py +0 -206
- 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/sdk/threshold/index.d.ts +0 -68
- package/sdk/threshold/index.d.ts.map +0 -1
- package/sdk/threshold/index.js +0 -254
- package/sdk/threshold/package-lock.json +0 -1361
- package/sdk/threshold/package.json +0 -39
- package/sdk/threshold/src/index.d.ts +0 -68
- package/sdk/threshold/src/index.d.ts.map +0 -1
- package/sdk/threshold/src/index.js +0 -254
- package/sdk/threshold/src/index.test.ts +0 -238
- package/sdk/threshold/src/index.ts +0 -355
- package/sdk/threshold/tsconfig.json +0 -19
- package/sdk/threshold/vitest.config.ts +0 -12
- 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/capability.test.ts +0 -504
- package/src/capability.ts +0 -380
- package/src/cborCodec.test.ts +0 -263
- package/src/cborCodec.ts +0 -339
- package/src/conformance.test.ts +0 -136
- package/src/conformanceVectors.ts +0 -99
- package/src/encryption.test.ts +0 -206
- package/src/encryption.ts +0 -245
- package/src/envelopeCbor.ts +0 -140
- 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 -246
- 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 -189
- package/src/index.ts +0 -39
- 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/otel.ts +0 -136
- 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.d.ts.map +0 -1
- package/src/protocol.js +0 -294
- package/src/protocol.test.ts +0 -155
- package/src/protocol.ts +0 -414
- 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 -273
- package/src/replayStores.ts +0 -215
- 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/stream.test.ts +0 -254
- package/src/stream.ts +0 -417
- package/src/telemetry.test.ts +0 -251
- package/src/telemetry.ts +0 -299
- 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 -200
- package/tsconfig.json +0 -15
- package/tsconfig.lib.json +0 -23
- package/vite.lib.config.ts +0 -16
- package/vitest.config.ts +0 -11
package/sdk/go/cbor.go
DELETED
|
@@ -1,551 +0,0 @@
|
|
|
1
|
-
// Package protocol7h3 — minimal deterministic CBOR encoder/decoder for ProtocolEnvelope.
|
|
2
|
-
// No external dependencies. Follows RFC 8949 §4.2 deterministic encoding.
|
|
3
|
-
//
|
|
4
|
-
// Envelope numeric field key scheme (matches TypeScript envelopeCbor.ts):
|
|
5
|
-
// Top-level: 1=header, 2=body, 3=signature(optional)
|
|
6
|
-
// Header: 1=version, 2=messageId, 3=timestampMs, 4=ttlMs, 5=sender, 6=recipient(opt), 7=nonce
|
|
7
|
-
// Body: 1=intent, 2=content, 3=capability(opt), 4=correlationId(opt)
|
|
8
|
-
// Signature: 1=alg, 2=keyId, 3=value
|
|
9
|
-
package protocol7h3
|
|
10
|
-
|
|
11
|
-
import (
|
|
12
|
-
"encoding/binary"
|
|
13
|
-
"fmt"
|
|
14
|
-
"math"
|
|
15
|
-
"sort"
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
// CBOR major types
|
|
19
|
-
const (
|
|
20
|
-
cborMTUint = 0
|
|
21
|
-
cborMTNint = 1
|
|
22
|
-
cborMTBstr = 2
|
|
23
|
-
cborMTTstr = 3
|
|
24
|
-
cborMTArray = 4
|
|
25
|
-
cborMTMap = 5
|
|
26
|
-
cborMTSimple = 7
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
// Additional info values
|
|
30
|
-
const (
|
|
31
|
-
cborAI1Byte = 24
|
|
32
|
-
cborAI2Byte = 25
|
|
33
|
-
cborAI4Byte = 26
|
|
34
|
-
cborAI8Byte = 27
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
// Simple values
|
|
38
|
-
const (
|
|
39
|
-
cborFalse = 0xf4
|
|
40
|
-
cborTrue = 0xf5
|
|
41
|
-
cborNull = 0xf6
|
|
42
|
-
cborFloat64 = 0xfb
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
// ─── encoder ────────────────────────────────────────────────────────────────
|
|
46
|
-
|
|
47
|
-
type cborEncoder struct {
|
|
48
|
-
buf []byte
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
func (e *cborEncoder) encodeHead(mt int, val uint64) {
|
|
52
|
-
base := byte(mt << 5)
|
|
53
|
-
switch {
|
|
54
|
-
case val <= 23:
|
|
55
|
-
e.buf = append(e.buf, base|byte(val))
|
|
56
|
-
case val <= 0xff:
|
|
57
|
-
e.buf = append(e.buf, base|cborAI1Byte, byte(val))
|
|
58
|
-
case val <= 0xffff:
|
|
59
|
-
e.buf = append(e.buf, base|cborAI2Byte, byte(val>>8), byte(val))
|
|
60
|
-
case val <= 0xffffffff:
|
|
61
|
-
b := [4]byte{}
|
|
62
|
-
binary.BigEndian.PutUint32(b[:], uint32(val))
|
|
63
|
-
e.buf = append(e.buf, base|cborAI4Byte)
|
|
64
|
-
e.buf = append(e.buf, b[:]...)
|
|
65
|
-
default:
|
|
66
|
-
b := [8]byte{}
|
|
67
|
-
binary.BigEndian.PutUint64(b[:], val)
|
|
68
|
-
e.buf = append(e.buf, base|cborAI8Byte)
|
|
69
|
-
e.buf = append(e.buf, b[:]...)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
func (e *cborEncoder) encodeUint(v uint64) {
|
|
74
|
-
e.encodeHead(cborMTUint, v)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
func (e *cborEncoder) encodeText(s string) {
|
|
78
|
-
b := []byte(s)
|
|
79
|
-
e.encodeHead(cborMTTstr, uint64(len(b)))
|
|
80
|
-
e.buf = append(e.buf, b...)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
func (e *cborEncoder) encodeFloat64(f float64) {
|
|
84
|
-
e.buf = append(e.buf, cborFloat64)
|
|
85
|
-
b := [8]byte{}
|
|
86
|
-
binary.BigEndian.PutUint64(b[:], math.Float64bits(f))
|
|
87
|
-
e.buf = append(e.buf, b[:]...)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// encodedKeyForUint returns the CBOR encoding of an unsigned integer key (for sorting).
|
|
91
|
-
func encodedKeyForUint(v uint64) []byte {
|
|
92
|
-
tmp := &cborEncoder{}
|
|
93
|
-
tmp.encodeHead(cborMTUint, v)
|
|
94
|
-
return tmp.buf
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// encodedKeyForText returns the CBOR encoding of a text string key (for sorting).
|
|
98
|
-
func encodedKeyForText(s string) []byte {
|
|
99
|
-
tmp := &cborEncoder{}
|
|
100
|
-
tmp.encodeText(s)
|
|
101
|
-
return tmp.buf
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
type intKV struct {
|
|
105
|
-
key uint64
|
|
106
|
-
keyEnc []byte
|
|
107
|
-
value interface{}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// encodeIntMap encodes a map with integer keys deterministically (RFC 8949 §4.2).
|
|
111
|
-
func (e *cborEncoder) encodeIntMap(pairs []intKV) {
|
|
112
|
-
// Sort by encoded key bytes (lexicographic)
|
|
113
|
-
sort.Slice(pairs, func(i, j int) bool {
|
|
114
|
-
a, b := pairs[i].keyEnc, pairs[j].keyEnc
|
|
115
|
-
for k := 0; k < len(a) && k < len(b); k++ {
|
|
116
|
-
if a[k] != b[k] {
|
|
117
|
-
return a[k] < b[k]
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return len(a) < len(b)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
e.encodeHead(cborMTMap, uint64(len(pairs)))
|
|
124
|
-
for _, kv := range pairs {
|
|
125
|
-
e.encodeHead(cborMTUint, kv.key)
|
|
126
|
-
e.encodeAny(kv.value)
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
func (e *cborEncoder) encodeAny(v interface{}) {
|
|
131
|
-
switch val := v.(type) {
|
|
132
|
-
case nil:
|
|
133
|
-
e.buf = append(e.buf, cborNull)
|
|
134
|
-
case bool:
|
|
135
|
-
if val {
|
|
136
|
-
e.buf = append(e.buf, cborTrue)
|
|
137
|
-
} else {
|
|
138
|
-
e.buf = append(e.buf, cborFalse)
|
|
139
|
-
}
|
|
140
|
-
case int:
|
|
141
|
-
if val >= 0 {
|
|
142
|
-
e.encodeHead(cborMTUint, uint64(val))
|
|
143
|
-
} else {
|
|
144
|
-
e.encodeHead(cborMTNint, uint64(-1-val))
|
|
145
|
-
}
|
|
146
|
-
case int64:
|
|
147
|
-
if val >= 0 {
|
|
148
|
-
e.encodeHead(cborMTUint, uint64(val))
|
|
149
|
-
} else {
|
|
150
|
-
e.encodeHead(cborMTNint, uint64(-1-val))
|
|
151
|
-
}
|
|
152
|
-
case uint64:
|
|
153
|
-
e.encodeHead(cborMTUint, val)
|
|
154
|
-
case float64:
|
|
155
|
-
e.encodeFloat64(val)
|
|
156
|
-
case string:
|
|
157
|
-
e.encodeText(val)
|
|
158
|
-
case []byte:
|
|
159
|
-
e.encodeHead(cborMTBstr, uint64(len(val)))
|
|
160
|
-
e.buf = append(e.buf, val...)
|
|
161
|
-
default:
|
|
162
|
-
panic(fmt.Sprintf("cborEncoder: unsupported type %T", v))
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// ─── decoder ────────────────────────────────────────────────────────────────
|
|
167
|
-
|
|
168
|
-
type cborDecoder struct {
|
|
169
|
-
data []byte
|
|
170
|
-
offset int
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
func (d *cborDecoder) remaining() int {
|
|
174
|
-
return len(d.data) - d.offset
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
func (d *cborDecoder) readByte() (byte, error) {
|
|
178
|
-
if d.remaining() < 1 {
|
|
179
|
-
return 0, fmt.Errorf("cbor: unexpected end of data")
|
|
180
|
-
}
|
|
181
|
-
b := d.data[d.offset]
|
|
182
|
-
d.offset++
|
|
183
|
-
return b, nil
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
func (d *cborDecoder) readN(n int) ([]byte, error) {
|
|
187
|
-
if d.remaining() < n {
|
|
188
|
-
return nil, fmt.Errorf("cbor: unexpected end of data")
|
|
189
|
-
}
|
|
190
|
-
out := d.data[d.offset : d.offset+n]
|
|
191
|
-
d.offset += n
|
|
192
|
-
return out, nil
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
func (d *cborDecoder) decodeHead() (mt int, val uint64, err error) {
|
|
196
|
-
b, err := d.readByte()
|
|
197
|
-
if err != nil {
|
|
198
|
-
return 0, 0, err
|
|
199
|
-
}
|
|
200
|
-
mt = int(b >> 5)
|
|
201
|
-
ai := b & 0x1f
|
|
202
|
-
|
|
203
|
-
switch {
|
|
204
|
-
case ai <= 23:
|
|
205
|
-
val = uint64(ai)
|
|
206
|
-
case ai == cborAI1Byte:
|
|
207
|
-
nb, err := d.readByte()
|
|
208
|
-
if err != nil {
|
|
209
|
-
return 0, 0, err
|
|
210
|
-
}
|
|
211
|
-
val = uint64(nb)
|
|
212
|
-
case ai == cborAI2Byte:
|
|
213
|
-
nb, err := d.readN(2)
|
|
214
|
-
if err != nil {
|
|
215
|
-
return 0, 0, err
|
|
216
|
-
}
|
|
217
|
-
val = uint64(binary.BigEndian.Uint16(nb))
|
|
218
|
-
case ai == cborAI4Byte:
|
|
219
|
-
nb, err := d.readN(4)
|
|
220
|
-
if err != nil {
|
|
221
|
-
return 0, 0, err
|
|
222
|
-
}
|
|
223
|
-
val = uint64(binary.BigEndian.Uint32(nb))
|
|
224
|
-
case ai == cborAI8Byte:
|
|
225
|
-
nb, err := d.readN(8)
|
|
226
|
-
if err != nil {
|
|
227
|
-
return 0, 0, err
|
|
228
|
-
}
|
|
229
|
-
val = binary.BigEndian.Uint64(nb)
|
|
230
|
-
default:
|
|
231
|
-
return 0, 0, fmt.Errorf("cbor: unsupported additional info %d", ai)
|
|
232
|
-
}
|
|
233
|
-
return mt, val, nil
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// decodeStringValue decodes a text string from the already-consumed initial byte context.
|
|
237
|
-
// The caller has already called decodeHead and got mt=3, val=length.
|
|
238
|
-
func (d *cborDecoder) readString(length uint64) (string, error) {
|
|
239
|
-
nb, err := d.readN(int(length))
|
|
240
|
-
if err != nil {
|
|
241
|
-
return "", err
|
|
242
|
-
}
|
|
243
|
-
return string(nb), nil
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// decodeIntMapFlat decodes a CBOR map with integer keys and string values.
|
|
247
|
-
// Returns a map[uint64]string. Handles int and string typed values.
|
|
248
|
-
func (d *cborDecoder) decodeIntStringMap() (map[uint64]string, error) {
|
|
249
|
-
mt, count, err := d.decodeHead()
|
|
250
|
-
if err != nil {
|
|
251
|
-
return nil, err
|
|
252
|
-
}
|
|
253
|
-
if mt != cborMTMap {
|
|
254
|
-
return nil, fmt.Errorf("cbor: expected map (mt=5) got mt=%d", mt)
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
result := make(map[uint64]string, count)
|
|
258
|
-
for i := uint64(0); i < count; i++ {
|
|
259
|
-
// Decode key (must be uint)
|
|
260
|
-
kmt, kval, err := d.decodeHead()
|
|
261
|
-
if err != nil {
|
|
262
|
-
return nil, err
|
|
263
|
-
}
|
|
264
|
-
if kmt != cborMTUint {
|
|
265
|
-
return nil, fmt.Errorf("cbor: expected uint key got mt=%d", kmt)
|
|
266
|
-
}
|
|
267
|
-
// Decode value — strings or ints
|
|
268
|
-
vmt, vval, err := d.decodeHead()
|
|
269
|
-
if err != nil {
|
|
270
|
-
return nil, err
|
|
271
|
-
}
|
|
272
|
-
switch vmt {
|
|
273
|
-
case cborMTTstr:
|
|
274
|
-
s, err := d.readString(vval)
|
|
275
|
-
if err != nil {
|
|
276
|
-
return nil, err
|
|
277
|
-
}
|
|
278
|
-
result[kval] = s
|
|
279
|
-
case cborMTUint:
|
|
280
|
-
result[kval] = fmt.Sprintf("%d", vval)
|
|
281
|
-
case cborMTNint:
|
|
282
|
-
result[kval] = fmt.Sprintf("%d", -int64(1)-int64(vval))
|
|
283
|
-
default:
|
|
284
|
-
return nil, fmt.Errorf("cbor: unsupported value type mt=%d at key %d", vmt, kval)
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
return result, nil
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// decodeIntMixedMap decodes a CBOR map with uint keys and mixed value types (string or int64).
|
|
291
|
-
func (d *cborDecoder) decodeIntMixedMap() (map[uint64]interface{}, error) {
|
|
292
|
-
mt, count, err := d.decodeHead()
|
|
293
|
-
if err != nil {
|
|
294
|
-
return nil, err
|
|
295
|
-
}
|
|
296
|
-
if mt != cborMTMap {
|
|
297
|
-
return nil, fmt.Errorf("cbor: expected map (mt=5) got mt=%d", mt)
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
result := make(map[uint64]interface{}, count)
|
|
301
|
-
for i := uint64(0); i < count; i++ {
|
|
302
|
-
kmt, kval, err := d.decodeHead()
|
|
303
|
-
if err != nil {
|
|
304
|
-
return nil, err
|
|
305
|
-
}
|
|
306
|
-
if kmt != cborMTUint {
|
|
307
|
-
return nil, fmt.Errorf("cbor: expected uint key got mt=%d", kmt)
|
|
308
|
-
}
|
|
309
|
-
vmt, vval, err := d.decodeHead()
|
|
310
|
-
if err != nil {
|
|
311
|
-
return nil, err
|
|
312
|
-
}
|
|
313
|
-
switch vmt {
|
|
314
|
-
case cborMTTstr:
|
|
315
|
-
s, err := d.readString(vval)
|
|
316
|
-
if err != nil {
|
|
317
|
-
return nil, err
|
|
318
|
-
}
|
|
319
|
-
result[kval] = s
|
|
320
|
-
case cborMTUint:
|
|
321
|
-
result[kval] = int64(vval)
|
|
322
|
-
case cborMTNint:
|
|
323
|
-
result[kval] = -int64(1) - int64(vval)
|
|
324
|
-
default:
|
|
325
|
-
return nil, fmt.Errorf("cbor: unsupported value type mt=%d at key %d", vmt, kval)
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
return result, nil
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// decodeTopMap decodes the top-level envelope map (uint keys → sub-maps).
|
|
332
|
-
// Returns the raw offsets for each sub-map so we can decode them individually.
|
|
333
|
-
func (d *cborDecoder) decodeTopLevel() (header map[uint64]interface{}, body map[uint64]interface{}, sig map[uint64]string, err error) {
|
|
334
|
-
mt, count, err := d.decodeHead()
|
|
335
|
-
if err != nil {
|
|
336
|
-
return nil, nil, nil, err
|
|
337
|
-
}
|
|
338
|
-
if mt != cborMTMap {
|
|
339
|
-
return nil, nil, nil, fmt.Errorf("cbor: expected map at top level")
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
for i := uint64(0); i < count; i++ {
|
|
343
|
-
kmt, kval, err := d.decodeHead()
|
|
344
|
-
if err != nil {
|
|
345
|
-
return nil, nil, nil, err
|
|
346
|
-
}
|
|
347
|
-
if kmt != cborMTUint {
|
|
348
|
-
return nil, nil, nil, fmt.Errorf("cbor: expected uint key at top level")
|
|
349
|
-
}
|
|
350
|
-
switch kval {
|
|
351
|
-
case 1: // header
|
|
352
|
-
header, err = d.decodeIntMixedMap()
|
|
353
|
-
if err != nil {
|
|
354
|
-
return nil, nil, nil, fmt.Errorf("cbor: decode header: %w", err)
|
|
355
|
-
}
|
|
356
|
-
case 2: // body
|
|
357
|
-
body, err = d.decodeIntMixedMap()
|
|
358
|
-
if err != nil {
|
|
359
|
-
return nil, nil, nil, fmt.Errorf("cbor: decode body: %w", err)
|
|
360
|
-
}
|
|
361
|
-
case 3: // signature (optional)
|
|
362
|
-
sig, err = d.decodeIntStringMap()
|
|
363
|
-
if err != nil {
|
|
364
|
-
return nil, nil, nil, fmt.Errorf("cbor: decode signature: %w", err)
|
|
365
|
-
}
|
|
366
|
-
default:
|
|
367
|
-
return nil, nil, nil, fmt.Errorf("cbor: unknown top-level key %d", kval)
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
return header, body, sig, nil
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// ─── public API ─────────────────────────────────────────────────────────────
|
|
374
|
-
|
|
375
|
-
// EncodeEnvelopeCBOR encodes a ProtocolEnvelope to CBOR bytes using numeric field keys.
|
|
376
|
-
func EncodeEnvelopeCBOR(env ProtocolEnvelope) ([]byte, error) {
|
|
377
|
-
e := &cborEncoder{}
|
|
378
|
-
|
|
379
|
-
// Count top-level entries: always header(1) + body(2), optionally sig(3)
|
|
380
|
-
topCount := 2
|
|
381
|
-
if env.Signature != nil {
|
|
382
|
-
topCount = 3
|
|
383
|
-
}
|
|
384
|
-
e.encodeHead(cborMTMap, uint64(topCount))
|
|
385
|
-
|
|
386
|
-
// Key 1: header
|
|
387
|
-
e.encodeHead(cborMTUint, 1)
|
|
388
|
-
{
|
|
389
|
-
headerCount := 6 // version, messageId, timestampMs, ttlMs, sender, nonce (always)
|
|
390
|
-
if env.Header.Recipient != "" {
|
|
391
|
-
headerCount = 7
|
|
392
|
-
}
|
|
393
|
-
headerPairs := []intKV{
|
|
394
|
-
{key: 1, keyEnc: encodedKeyForUint(1), value: env.Header.Version},
|
|
395
|
-
{key: 2, keyEnc: encodedKeyForUint(2), value: env.Header.MessageID},
|
|
396
|
-
{key: 3, keyEnc: encodedKeyForUint(3), value: env.Header.TimestampMs},
|
|
397
|
-
{key: 4, keyEnc: encodedKeyForUint(4), value: env.Header.TTLMs},
|
|
398
|
-
{key: 5, keyEnc: encodedKeyForUint(5), value: env.Header.Sender},
|
|
399
|
-
{key: 7, keyEnc: encodedKeyForUint(7), value: env.Header.Nonce},
|
|
400
|
-
}
|
|
401
|
-
if env.Header.Recipient != "" {
|
|
402
|
-
headerPairs = append(headerPairs, intKV{key: 6, keyEnc: encodedKeyForUint(6), value: env.Header.Recipient})
|
|
403
|
-
}
|
|
404
|
-
_ = headerCount
|
|
405
|
-
e.encodeIntMap(headerPairs)
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// Key 2: body
|
|
409
|
-
e.encodeHead(cborMTUint, 2)
|
|
410
|
-
{
|
|
411
|
-
bodyPairs := []intKV{
|
|
412
|
-
{key: 1, keyEnc: encodedKeyForUint(1), value: env.Body.Intent},
|
|
413
|
-
{key: 2, keyEnc: encodedKeyForUint(2), value: env.Body.Content},
|
|
414
|
-
}
|
|
415
|
-
if env.Body.Capability != "" {
|
|
416
|
-
bodyPairs = append(bodyPairs, intKV{key: 3, keyEnc: encodedKeyForUint(3), value: env.Body.Capability})
|
|
417
|
-
}
|
|
418
|
-
if env.Body.CorrelationID != "" {
|
|
419
|
-
bodyPairs = append(bodyPairs, intKV{key: 4, keyEnc: encodedKeyForUint(4), value: env.Body.CorrelationID})
|
|
420
|
-
}
|
|
421
|
-
e.encodeIntMap(bodyPairs)
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// Key 3: signature (optional)
|
|
425
|
-
if env.Signature != nil {
|
|
426
|
-
e.encodeHead(cborMTUint, 3)
|
|
427
|
-
sigPairs := []intKV{
|
|
428
|
-
{key: 1, keyEnc: encodedKeyForUint(1), value: env.Signature.Alg},
|
|
429
|
-
{key: 2, keyEnc: encodedKeyForUint(2), value: env.Signature.KeyID},
|
|
430
|
-
{key: 3, keyEnc: encodedKeyForUint(3), value: env.Signature.Value},
|
|
431
|
-
}
|
|
432
|
-
e.encodeIntMap(sigPairs)
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
return e.buf, nil
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// DecodeEnvelopeCBOR decodes CBOR bytes into a ProtocolEnvelope.
|
|
439
|
-
func DecodeEnvelopeCBOR(data []byte) (ProtocolEnvelope, error) {
|
|
440
|
-
d := &cborDecoder{data: data}
|
|
441
|
-
|
|
442
|
-
header, body, sig, err := d.decodeTopLevel()
|
|
443
|
-
if err != nil {
|
|
444
|
-
return ProtocolEnvelope{}, fmt.Errorf("DecodeEnvelopeCBOR: %w", err)
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
if header == nil {
|
|
448
|
-
return ProtocolEnvelope{}, fmt.Errorf("DecodeEnvelopeCBOR: missing header (key 1)")
|
|
449
|
-
}
|
|
450
|
-
if body == nil {
|
|
451
|
-
return ProtocolEnvelope{}, fmt.Errorf("DecodeEnvelopeCBOR: missing body (key 2)")
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
getString := func(m map[uint64]interface{}, key uint64, field string) (string, error) {
|
|
455
|
-
v, ok := m[key]
|
|
456
|
-
if !ok {
|
|
457
|
-
return "", fmt.Errorf("DecodeEnvelopeCBOR: missing field %s (key %d)", field, key)
|
|
458
|
-
}
|
|
459
|
-
s, ok := v.(string)
|
|
460
|
-
if !ok {
|
|
461
|
-
return "", fmt.Errorf("DecodeEnvelopeCBOR: field %s (key %d) is not a string", field, key)
|
|
462
|
-
}
|
|
463
|
-
return s, nil
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
getInt64 := func(m map[uint64]interface{}, key uint64, field string) (int64, error) {
|
|
467
|
-
v, ok := m[key]
|
|
468
|
-
if !ok {
|
|
469
|
-
return 0, fmt.Errorf("DecodeEnvelopeCBOR: missing field %s (key %d)", field, key)
|
|
470
|
-
}
|
|
471
|
-
n, ok := v.(int64)
|
|
472
|
-
if !ok {
|
|
473
|
-
return 0, fmt.Errorf("DecodeEnvelopeCBOR: field %s (key %d) is not an int", field, key)
|
|
474
|
-
}
|
|
475
|
-
return n, nil
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
getOptString := func(m map[uint64]interface{}, key uint64) string {
|
|
479
|
-
v, ok := m[key]
|
|
480
|
-
if !ok {
|
|
481
|
-
return ""
|
|
482
|
-
}
|
|
483
|
-
s, _ := v.(string)
|
|
484
|
-
return s
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
version, err := getString(header, 1, "version")
|
|
488
|
-
if err != nil {
|
|
489
|
-
return ProtocolEnvelope{}, err
|
|
490
|
-
}
|
|
491
|
-
messageID, err := getString(header, 2, "messageId")
|
|
492
|
-
if err != nil {
|
|
493
|
-
return ProtocolEnvelope{}, err
|
|
494
|
-
}
|
|
495
|
-
timestampMs, err := getInt64(header, 3, "timestampMs")
|
|
496
|
-
if err != nil {
|
|
497
|
-
return ProtocolEnvelope{}, err
|
|
498
|
-
}
|
|
499
|
-
ttlMs, err := getInt64(header, 4, "ttlMs")
|
|
500
|
-
if err != nil {
|
|
501
|
-
return ProtocolEnvelope{}, err
|
|
502
|
-
}
|
|
503
|
-
sender, err := getString(header, 5, "sender")
|
|
504
|
-
if err != nil {
|
|
505
|
-
return ProtocolEnvelope{}, err
|
|
506
|
-
}
|
|
507
|
-
nonce, err := getString(header, 7, "nonce")
|
|
508
|
-
if err != nil {
|
|
509
|
-
return ProtocolEnvelope{}, err
|
|
510
|
-
}
|
|
511
|
-
recipient := getOptString(header, 6)
|
|
512
|
-
|
|
513
|
-
intent, err := getString(body, 1, "intent")
|
|
514
|
-
if err != nil {
|
|
515
|
-
return ProtocolEnvelope{}, err
|
|
516
|
-
}
|
|
517
|
-
content, err := getString(body, 2, "content")
|
|
518
|
-
if err != nil {
|
|
519
|
-
return ProtocolEnvelope{}, err
|
|
520
|
-
}
|
|
521
|
-
capability := getOptString(body, 3)
|
|
522
|
-
correlationID := getOptString(body, 4)
|
|
523
|
-
|
|
524
|
-
env := ProtocolEnvelope{
|
|
525
|
-
Header: ProtocolHeader{
|
|
526
|
-
Version: version,
|
|
527
|
-
MessageID: messageID,
|
|
528
|
-
TimestampMs: timestampMs,
|
|
529
|
-
TTLMs: ttlMs,
|
|
530
|
-
Sender: sender,
|
|
531
|
-
Recipient: recipient,
|
|
532
|
-
Nonce: nonce,
|
|
533
|
-
},
|
|
534
|
-
Body: ProtocolBody{
|
|
535
|
-
Intent: intent,
|
|
536
|
-
Content: content,
|
|
537
|
-
Capability: capability,
|
|
538
|
-
CorrelationID: correlationID,
|
|
539
|
-
},
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
if sig != nil {
|
|
543
|
-
env.Signature = &ProtocolSignature{
|
|
544
|
-
Alg: sig[1],
|
|
545
|
-
KeyID: sig[2],
|
|
546
|
-
Value: sig[3],
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
return env, nil
|
|
551
|
-
}
|