@cello-protocol/protocol-types 0.0.22 → 0.0.24
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/dist/cbor.d.ts +21 -1
- package/dist/cbor.d.ts.map +1 -1
- package/dist/cbor.js +21 -1
- package/dist/cbor.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/primary-transfer.d.ts +1 -1
- package/dist/primary-transfer.d.ts.map +1 -1
- package/dist/primary-transfer.js +11 -1
- package/dist/primary-transfer.js.map +1 -1
- package/dist/trust-signal.d.ts +115 -0
- package/dist/trust-signal.d.ts.map +1 -0
- package/dist/trust-signal.js +316 -0
- package/dist/trust-signal.js.map +1 -0
- package/package.json +6 -3
- package/test/vectors/connection-package-canonical.json +10 -0
- package/test/vectors/envelope-v1-canonical.json +16 -0
- package/test/vectors/genesis-prev-root.json +53 -0
- package/test/vectors/scan-result-unscanned.json +5 -0
- package/test/vectors/structure1-canonical.json +13 -0
- package/test/vectors/structure2-canonical.json +12 -0
- package/test/vectors/tbs-v0-canonical.json +8 -0
- package/test/vectors/trust-signal-envelope-canonical.json +136 -0
package/dist/cbor.d.ts
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Encode to CBOR: byte strings for bytes, maps for objects. Valid RFC 8949.
|
|
3
|
+
*
|
|
4
|
+
* NOT RFC 8949 §4.2 deterministic FOR MAPS, and anything hashed or signed must account for that.
|
|
5
|
+
* Measured (M10 / DOD-CBOR-1, journal Entry 4):
|
|
6
|
+
*
|
|
7
|
+
* encode({b:1, a:2}) -> b9 0002 6162 01 6161 02
|
|
8
|
+
* encode({a:2, b:1}) -> b9 0002 6161 02 6162 01 <- different bytes, same object
|
|
9
|
+
*
|
|
10
|
+
* Two departures from Core Deterministic Encoding, both map-only: keys follow INSERTION ORDER
|
|
11
|
+
* rather than bytewise sort, and the map header is not minimal-length (`b9 0002` for a 2-entry map
|
|
12
|
+
* where CDE requires `a2`).
|
|
13
|
+
*
|
|
14
|
+
* ARRAYS, text strings, byte strings, integers and null ARE minimal and order-fixed. That is why
|
|
15
|
+
* every to-be-signed structure in CELLO is an ARRAY with a domain tag in slot 0 —
|
|
16
|
+
* buildAgentRevocationTbs, buildPrimaryTransferTbs, buildSealTbs, buildParkContentTbs,
|
|
17
|
+
* encodeTrustSignalEnvelope. Two parties encoding the same array always produce the same bytes;
|
|
18
|
+
* two parties encoding the same MAP do not, if they built it in a different field order.
|
|
19
|
+
*
|
|
20
|
+
* So: never hash or sign a CBOR map produced by this encoder. Put the fields in a fixed-order array.
|
|
21
|
+
*/
|
|
2
22
|
export declare function encodeCbor(value: unknown): Uint8Array;
|
|
3
23
|
/** Decode CBOR. Tolerates the older tag-64 and record encodings so pre-migration data still reads. */
|
|
4
24
|
export declare function decodeCbor(bytes: Uint8Array): unknown;
|
package/dist/cbor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cbor.d.ts","sourceRoot":"","sources":["../src/cbor.ts"],"names":[],"mappings":"AAwBA
|
|
1
|
+
{"version":3,"file":"cbor.d.ts","sourceRoot":"","sources":["../src/cbor.ts"],"names":[],"mappings":"AAwBA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAErD;AAED,sGAAsG;AACtG,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAErD"}
|
package/dist/cbor.js
CHANGED
|
@@ -20,7 +20,27 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { Encoder, decode } from "cbor-x";
|
|
22
22
|
const ENCODER = new Encoder({ tagUint8Array: false, useRecords: false });
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Encode to CBOR: byte strings for bytes, maps for objects. Valid RFC 8949.
|
|
25
|
+
*
|
|
26
|
+
* NOT RFC 8949 §4.2 deterministic FOR MAPS, and anything hashed or signed must account for that.
|
|
27
|
+
* Measured (M10 / DOD-CBOR-1, journal Entry 4):
|
|
28
|
+
*
|
|
29
|
+
* encode({b:1, a:2}) -> b9 0002 6162 01 6161 02
|
|
30
|
+
* encode({a:2, b:1}) -> b9 0002 6161 02 6162 01 <- different bytes, same object
|
|
31
|
+
*
|
|
32
|
+
* Two departures from Core Deterministic Encoding, both map-only: keys follow INSERTION ORDER
|
|
33
|
+
* rather than bytewise sort, and the map header is not minimal-length (`b9 0002` for a 2-entry map
|
|
34
|
+
* where CDE requires `a2`).
|
|
35
|
+
*
|
|
36
|
+
* ARRAYS, text strings, byte strings, integers and null ARE minimal and order-fixed. That is why
|
|
37
|
+
* every to-be-signed structure in CELLO is an ARRAY with a domain tag in slot 0 —
|
|
38
|
+
* buildAgentRevocationTbs, buildPrimaryTransferTbs, buildSealTbs, buildParkContentTbs,
|
|
39
|
+
* encodeTrustSignalEnvelope. Two parties encoding the same array always produce the same bytes;
|
|
40
|
+
* two parties encoding the same MAP do not, if they built it in a different field order.
|
|
41
|
+
*
|
|
42
|
+
* So: never hash or sign a CBOR map produced by this encoder. Put the fields in a fixed-order array.
|
|
43
|
+
*/
|
|
24
44
|
export function encodeCbor(value) {
|
|
25
45
|
return ENCODER.encode(value);
|
|
26
46
|
}
|
package/dist/cbor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cbor.js","sourceRoot":"","sources":["../src/cbor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEzC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;AAEzE
|
|
1
|
+
{"version":3,"file":"cbor.js","sourceRoot":"","sources":["../src/cbor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEzC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAe,CAAC;AAC7C,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,UAAU,CAAC,KAAiB;IAC1C,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { encodeCbor, decodeCbor } from "./cbor.js";
|
|
2
|
+
export { TRUST_SIGNAL_DOMAIN, encodeTrustSignalEnvelope, decodeTrustSignalEnvelope, hashTrustSignalEnvelope, verifyTrustSignalHash, } from "./trust-signal.js";
|
|
3
|
+
export type { TrustSignalEnvelope, SignalSubjectKind, SignalIssuerKind, } from "./trust-signal.js";
|
|
2
4
|
export type { MessageEnvelope, MessageEnvelopeV1, EnvelopeError, BuildResult, BuildResultV1, ValidateResult, ValidateResultV1, DeserializeResult, DeserializeResultV1, } from "./types.js";
|
|
3
5
|
export { MAX_CONTENT_BYTES } from "./limits.js";
|
|
4
6
|
export { encodeStructure1, STRUCTURE1_VERSION } from "./structure1.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAKnD,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEvE,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,4BAA4B,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACjK,YAAY,EACV,iBAAiB,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,eAAe,EAAE,iBAAiB,EAAE,WAAW,EACnH,gBAAgB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,aAAa,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,YAAY,EAChI,eAAe,EAAE,cAAc,EAAE,yBAAyB,EAAE,0BAA0B,GACvF,MAAM,cAAc,CAAC;AAEtB,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,2BAA2B,EAC3B,2BAA2B,EAC3B,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,2BAA2B,EAC3B,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,yBAAyB,EACzB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AAGjC,YAAY,EACV,eAAe,EACf,WAAW,EACX,QAAQ,EACR,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,YAAY,EACZ,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEzF,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACnF,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EACV,iBAAiB,EACjB,wBAAwB,EACxB,kBAAkB,EAClB,yBAAyB,EACzB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,4BAA4B,EAC5B,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,kBAAkB,EAClB,yBAAyB,EACzB,gBAAgB,EAChB,wBAAwB,EACxB,sBAAsB,EACtB,gBAAgB,EAChB,2BAA2B,GAC5B,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EACf,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACV,wBAAwB,EACxB,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,EACzB,0BAA0B,EAC1B,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAGvB,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,+BAA+B,GAChC,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,6BAA6B,EAC7B,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export { encodeCbor, decodeCbor } from "./cbor.js";
|
|
2
|
+
// M10 / DOD-CBOR-1 — the canonical trust-signal envelope. ONE implementation, consumed by the
|
|
3
|
+
// portal (mint), the directory (submission + presentation), and both daemons (receipt +
|
|
4
|
+
// verification) — M10-D16.
|
|
5
|
+
export { TRUST_SIGNAL_DOMAIN, encodeTrustSignalEnvelope, decodeTrustSignalEnvelope, hashTrustSignalEnvelope, verifyTrustSignalHash, } from "./trust-signal.js";
|
|
2
6
|
export { MAX_CONTENT_BYTES } from "./limits.js";
|
|
3
7
|
export { encodeStructure1, STRUCTURE1_VERSION } from "./structure1.js";
|
|
4
8
|
export { SCAN_RESULT_SENTINEL, buildStructure2, encodeStructure2, encodeScanResultSentinel, verifyStructure2Signature, } from "./structure2.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEnD,8FAA8F;AAC9F,wFAAwF;AACxF,2BAA2B;AAC3B,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAmB3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAGvE,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,4BAA4B,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AA0BjK,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,yBAAyB,EACzB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AAmBjC,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEzF,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AA6DnF,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAuBvB,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAO/B,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,6BAA6B,EAC7B,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAE/B,wFAAwF;AACxF,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -77,7 +77,7 @@ export declare const PRIMARY_TRANSFER_DOMAIN = "CELLO-PRIMARY-TRANSFER-v1";
|
|
|
77
77
|
* produce IDENTICAL bytes, or verification never succeeds regardless of whether the ceremony
|
|
78
78
|
* itself was genuine. Mirrors buildAgentRevocationTbs's exact structure (revocation.ts).
|
|
79
79
|
*/
|
|
80
|
-
export declare function buildPrimaryTransferTbs(kLocalPubkeyHex: string, newDaemonId: string, oldDaemonId: string, nonce: string, timestamp: number): Uint8Array;
|
|
80
|
+
export declare function buildPrimaryTransferTbs(kLocalPubkeyHex: string, newDaemonId: string, oldDaemonId: string, nonce: string, timestamp: number | bigint): Uint8Array;
|
|
81
81
|
/**
|
|
82
82
|
* Step 1: the new Primary attests a transfer to one directory node. Sent on that node's
|
|
83
83
|
* authenticated signaling stream. The daemon repeats this per node it dials.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primary-transfer.d.ts","sourceRoot":"","sources":["../src/primary-transfer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AAKH;;;mEAGmE;AACnE,eAAO,MAAM,uBAAuB,8BAA8B,CAAC;AAEnE;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"primary-transfer.d.ts","sourceRoot":"","sources":["../src/primary-transfer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AAKH;;;mEAGmE;AACnE,eAAO,MAAM,uBAAuB,8BAA8B,CAAC;AAEnE;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAAG,MAAM,GACzB,UAAU,CAmBZ;AAID;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,0BAA0B,CAAC;IACjC,yFAAyF;IACzF,cAAc,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,aAAa,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oFAAoF;IACpF,KAAK,EAAE,MAAM,CAAC;IACd,oGAAoG;IACpG,SAAS,EAAE,MAAM,CAAC;CACnB;AAID;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,MAAM,EAAE,sBAAsB,GAAG,cAAc,GAAG,eAAe,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;CACzG"}
|
package/dist/primary-transfer.js
CHANGED
|
@@ -79,13 +79,23 @@ export const PRIMARY_TRANSFER_DOMAIN = "CELLO-PRIMARY-TRANSFER-v1";
|
|
|
79
79
|
* itself was genuine. Mirrors buildAgentRevocationTbs's exact structure (revocation.ts).
|
|
80
80
|
*/
|
|
81
81
|
export function buildPrimaryTransferTbs(kLocalPubkeyHex, newDaemonId, oldDaemonId, nonce, timestamp) {
|
|
82
|
+
// Past 0xffffffff, cbor-x encodes a JS `number` as an IEEE float64 (`fb`), not a uint64 (`1b`) —
|
|
83
|
+
// so a MILLISECOND timestamp (Date.now() ≈ 1.77e12, which is what a caller will reach for) would
|
|
84
|
+
// be hashed as a float, and any non-cbor-x verifier would compute different TBS bytes and reject a
|
|
85
|
+
// genuine transfer. buildSealTbs (session.ts:160,271) and buildAgentRevocationTbs
|
|
86
|
+
// (revocation.ts:39) both carry this coercion; this builder shipped without it.
|
|
87
|
+
//
|
|
88
|
+
// Safe to add now: there is no client-side sender yet (`primary_transfer_request` has no producer
|
|
89
|
+
// in cello-client), so no signature exists over these bytes, and every timestamp below 2^32
|
|
90
|
+
// encodes byte-identically to before.
|
|
91
|
+
const tsEncoded = typeof timestamp === "bigint" || timestamp > 0xffffffff ? BigInt(timestamp) : timestamp;
|
|
82
92
|
return encodeCbor([
|
|
83
93
|
PRIMARY_TRANSFER_DOMAIN,
|
|
84
94
|
kLocalPubkeyHex,
|
|
85
95
|
newDaemonId,
|
|
86
96
|
oldDaemonId,
|
|
87
97
|
nonce,
|
|
88
|
-
|
|
98
|
+
tsEncoded,
|
|
89
99
|
]);
|
|
90
100
|
}
|
|
91
101
|
//# sourceMappingURL=primary-transfer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primary-transfer.js","sourceRoot":"","sources":["../src/primary-transfer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC;;;mEAGmE;AACnE,MAAM,CAAC,MAAM,uBAAuB,GAAG,2BAA2B,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACrC,eAAuB,EACvB,WAAmB,EACnB,WAAmB,EACnB,KAAa,EACb,
|
|
1
|
+
{"version":3,"file":"primary-transfer.js","sourceRoot":"","sources":["../src/primary-transfer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC;;;mEAGmE;AACnE,MAAM,CAAC,MAAM,uBAAuB,GAAG,2BAA2B,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACrC,eAAuB,EACvB,WAAmB,EACnB,WAAmB,EACnB,KAAa,EACb,SAA0B;IAE1B,iGAAiG;IACjG,iGAAiG;IACjG,mGAAmG;IACnG,kFAAkF;IAClF,gFAAgF;IAChF,EAAE;IACF,kGAAkG;IAClG,4FAA4F;IAC5F,sCAAsC;IACtC,MAAM,SAAS,GAAG,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1G,OAAO,UAAU,CAAC;QAChB,uBAAuB;QACvB,eAAe;QACf,WAAW;QACX,WAAW;QACX,KAAK;QACL,SAAS;KACV,CAAe,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical trust-signal envelope (M10 / DOD-CBOR-1): serialize, hash, verify.
|
|
3
|
+
*
|
|
4
|
+
* Four parties independently re-derive this hash — the portal at mint, the directory at submission
|
|
5
|
+
* (INV-CHOKEPOINT's re-hash before store), the directory again at presentation (dumb check 1), and
|
|
6
|
+
* the holder/recipient daemons on receipt and at verification. They must agree byte-for-byte,
|
|
7
|
+
* forever, across three repos and two languages' worth of tooling. A single divergent byte turns a
|
|
8
|
+
* valid signal into a false `hash_mismatch` — unpresentable, and censorship-shaped, because it can
|
|
9
|
+
* differ per node or per client version.
|
|
10
|
+
*
|
|
11
|
+
* THE PREIMAGE IS AN ARRAY, NOT A MAP, AND THAT IS LOAD-BEARING (M10-D15).
|
|
12
|
+
* The shared encoder (`cbor.ts`) is not RFC 8949 §4.2 deterministic for MAPS: map keys follow
|
|
13
|
+
* INSERTION ORDER, and map headers are not minimal-length (a 2-entry map emits `b9 0002`, not `a2`).
|
|
14
|
+
* Arrays, text strings, byte strings, integers and null are all minimal and order-fixed. Encoding
|
|
15
|
+
* the preimage as a fixed-order array therefore makes determinism STRUCTURAL — a property of the
|
|
16
|
+
* shape, not of the encoder's configuration — and costs no encoder change and no migration of the
|
|
17
|
+
* blobs already on disk. Every signed TBS in CELLO is an array for this same reason
|
|
18
|
+
* (`buildAgentRevocationTbs`, `buildPrimaryTransferTbs`, `buildSealTbs`, `buildParkContentTbs`).
|
|
19
|
+
*
|
|
20
|
+
* Consequences, all enforced below:
|
|
21
|
+
* - FIELD ORDER IS THE WIRE FORMAT. Reordering the array is a breaking hash change, not a
|
|
22
|
+
* refactor. Retrofitting a canonical form later breaks every hash already minted (spec §5).
|
|
23
|
+
* - THE FIELD SET IS CLOSED (spec §4). An unknown field is REJECTED, never ignored: silently
|
|
24
|
+
* dropping it would let two parties who disagree about the field set still agree on the hash,
|
|
25
|
+
* making the extra field unauthenticated data riding inside a "verified" signal.
|
|
26
|
+
* - `status` / `class` / `verified_at` ARE NOT IN THE PREIMAGE. They are mutable after minting —
|
|
27
|
+
* that is the entire point of excluding them. If `status` were hashed, revoking a signal would
|
|
28
|
+
* change its hash and the directory could never find it again.
|
|
29
|
+
* - OPTIONAL FIELDS ARE AN EXPLICIT `null` IN A FIXED SLOT, NEVER OMITTED (M10-D17). In an array,
|
|
30
|
+
* omitting a field shifts every later field and changes the arity, so an absent `expires_at`
|
|
31
|
+
* becomes confusable with a misaligned `supersedes_hash`.
|
|
32
|
+
* - NO FLOATING POINT. Timestamps are integer epoch SECONDS. A float would not survive
|
|
33
|
+
* byte-agreement across languages.
|
|
34
|
+
* - `payload` IS OPAQUE BYTES, never decoded or re-encoded. A payload parsed and re-serialized
|
|
35
|
+
* would change bytes under a different encoder version. This is also what INV-ZERO-BUMP rests
|
|
36
|
+
* on: a type this code has never seen must hash and flow through untouched.
|
|
37
|
+
*/
|
|
38
|
+
/** Domain separation, bound as element 0 of the preimage array — the house convention
|
|
39
|
+
* (`AGENT_REVOCATION_DOMAIN`, `PRIMARY_TRANSFER_DOMAIN`). A trust-signal hash can therefore never
|
|
40
|
+
* collide with, or be replayed as, any other hashed/signed CELLO structure. */
|
|
41
|
+
export declare const TRUST_SIGNAL_DOMAIN = "CELLO-TSIG-v1";
|
|
42
|
+
/** Whose fact this is. Account-subject signals (phone, email, social) are presentable by every agent
|
|
43
|
+
* under the account; agent-subject signals (track record) belong to one agent. Both are HASHED, so
|
|
44
|
+
* the scope cannot be changed after minting (M10-D5). */
|
|
45
|
+
export type SignalSubjectKind = "account" | "agent";
|
|
46
|
+
/** Who attested it. Drives FRAMING at the consuming LLM (INV-FRAMING): `portal` is portal-attested;
|
|
47
|
+
* `agent` is quoted-untrusted ("Bob says:"). Hashed, so framing cannot be laundered by a relabel. */
|
|
48
|
+
export type SignalIssuerKind = "portal" | "agent";
|
|
49
|
+
/**
|
|
50
|
+
* The hashed part of a trust signal. This is the WHOLE preimage and nothing else — see spec §4's
|
|
51
|
+
* mandatory-disclosure set. `type` is an OPAQUE STRING here and everywhere in the client and the
|
|
52
|
+
* directory: never an enum, never switched on (INV-ZERO-BUMP).
|
|
53
|
+
*/
|
|
54
|
+
export interface TrustSignalEnvelope {
|
|
55
|
+
subject_kind: SignalSubjectKind;
|
|
56
|
+
/** The account id or agent id this fact is about. */
|
|
57
|
+
subject: string;
|
|
58
|
+
issuer_kind: SignalIssuerKind;
|
|
59
|
+
/** Hex-encoded Ed25519 public key of the issuer. Verified against the directory's authorized set. */
|
|
60
|
+
issuer_pubkey: string;
|
|
61
|
+
/** OPAQUE type string. Adding a type must require no code change anywhere but the portal. */
|
|
62
|
+
type: string;
|
|
63
|
+
schema_version: number;
|
|
64
|
+
/** OPAQUE payload bytes. Never parsed, never re-encoded, never hoisted into a column. */
|
|
65
|
+
payload: Uint8Array;
|
|
66
|
+
/** Integer epoch SECONDS. */
|
|
67
|
+
issued_at: number;
|
|
68
|
+
/** Integer epoch SECONDS, or null for a signal that never expires. */
|
|
69
|
+
expires_at: number | null;
|
|
70
|
+
/** The 32-byte hash this envelope replaces, or null for a first mint. */
|
|
71
|
+
supersedes_hash: Uint8Array | null;
|
|
72
|
+
}
|
|
73
|
+
/** The canonical preimage bytes. Deterministic across every party that runs this code. */
|
|
74
|
+
export declare function encodeTrustSignalEnvelope(envelope: TrustSignalEnvelope): Uint8Array;
|
|
75
|
+
/** The signal's identity: SHA-256 over the canonical preimage. This is the `signal_hash` that the
|
|
76
|
+
* directory stores, the holder presents, and the recipient re-derives. */
|
|
77
|
+
export declare function hashTrustSignalEnvelope(envelope: TrustSignalEnvelope): Uint8Array;
|
|
78
|
+
/**
|
|
79
|
+
* Does this envelope actually hash to `expected`? Length is checked first, so a truncated hash can
|
|
80
|
+
* never pass by matching a prefix. The comparison is constant-time in the length of the input: a
|
|
81
|
+
* signal hash is public, but the habit is cheap and the alternative invites a timing oracle the day
|
|
82
|
+
* one of these stops being public.
|
|
83
|
+
*
|
|
84
|
+
* ⚠️ THIS RETURNS `false` FOR A WRONG HASH BUT **THROWS** FOR A MALFORMED ENVELOPE, AND THAT
|
|
85
|
+
* ASYMMETRY IS DELIBERATE. A wrong hash is a normal, expected answer ("no, this doesn't match"). A
|
|
86
|
+
* malformed envelope is not an answer at all — it is an envelope that cannot be canonicalized, so
|
|
87
|
+
* there is no hash to compare and any boolean would be a lie.
|
|
88
|
+
*
|
|
89
|
+
* The directory calls this on hostile input. DO NOT wrap it in `try { … } catch { return false }`:
|
|
90
|
+
* that converts "this envelope is unhashable garbage" into "this envelope simply didn't match",
|
|
91
|
+
* which is the silent swallow that hides the attack. Let it throw, and log the cause.
|
|
92
|
+
*/
|
|
93
|
+
export declare function verifyTrustSignalHash(envelope: TrustSignalEnvelope, expected: Uint8Array): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Decode canonical envelope bytes back into the envelope — the inverse of `encodeTrustSignalEnvelope`,
|
|
96
|
+
* and the ONE decoder every party shares (INV-CANONICAL / M10-D7 — the holder's daemon that RECEIVES a
|
|
97
|
+
* delivered signal must decode with the SAME code the directory and portal encode with, never a vendored
|
|
98
|
+
* copy). The preimage is a fixed-order 11-element ARRAY (M10-D15); element 0 is the domain tag.
|
|
99
|
+
*
|
|
100
|
+
* REFUSES anything that is not EXACTLY canonical: it re-encodes the decoded envelope with
|
|
101
|
+
* `encodeTrustSignalEnvelope` and compares the bytes to the input. If they differ — a number that came
|
|
102
|
+
* back as a float, a byte string mis-read, a non-minimal integer, trailing bytes — it THROWS rather than
|
|
103
|
+
* return a "best-effort" envelope: a best-effort hash is one two parties can disagree about. Reusing the
|
|
104
|
+
* encoder (not a hand-rolled re-encode) guarantees the decoder cannot drift from it, AND runs the encoder's
|
|
105
|
+
* own field validation (epoch-seconds bounds, payload-is-bytes, 32-byte supersedes_hash) — so a
|
|
106
|
+
* canonical-at-the-byte-level-but-semantically-invalid array (e.g. an out-of-range subject_kind) still
|
|
107
|
+
* throws here rather than escaping as a bad envelope.
|
|
108
|
+
*
|
|
109
|
+
* ⚠️ THROWS on any malformed/non-canonical input (never returns a partial). The holder's chokepoint
|
|
110
|
+
* (`deliverWalletSignal`) and the recipient's verify both depend on that: a delivery that does not
|
|
111
|
+
* round-trip is corrupt or tampered and must not be stored. Do NOT wrap in try/catch → default — that is
|
|
112
|
+
* the silent swallow that turns "unhashable garbage" into "a valid-looking empty signal".
|
|
113
|
+
*/
|
|
114
|
+
export declare function decodeTrustSignalEnvelope(bytes: Uint8Array): TrustSignalEnvelope;
|
|
115
|
+
//# sourceMappingURL=trust-signal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust-signal.d.ts","sourceRoot":"","sources":["../src/trust-signal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAKH;;gFAEgF;AAChF,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AAEnD;;0DAE0D;AAC1D,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpD;sGACsG;AACtG,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAElD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,iBAAiB,CAAC;IAChC,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,gBAAgB,CAAC;IAC9B,qGAAqG;IACrG,aAAa,EAAE,MAAM,CAAC;IACtB,6FAA6F;IAC7F,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,yFAAyF;IACzF,OAAO,EAAE,UAAU,CAAC;IACpB,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,yEAAyE;IACzE,eAAe,EAAE,UAAU,GAAG,IAAI,CAAC;CACpC;AAmND,0FAA0F;AAC1F,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,UAAU,CAEnF;AAED;2EAC2E;AAC3E,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,UAAU,CAEjF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,mBAAmB,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO,CAMlG;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,UAAU,GAAG,mBAAmB,CA6ChF"}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical trust-signal envelope (M10 / DOD-CBOR-1): serialize, hash, verify.
|
|
3
|
+
*
|
|
4
|
+
* Four parties independently re-derive this hash — the portal at mint, the directory at submission
|
|
5
|
+
* (INV-CHOKEPOINT's re-hash before store), the directory again at presentation (dumb check 1), and
|
|
6
|
+
* the holder/recipient daemons on receipt and at verification. They must agree byte-for-byte,
|
|
7
|
+
* forever, across three repos and two languages' worth of tooling. A single divergent byte turns a
|
|
8
|
+
* valid signal into a false `hash_mismatch` — unpresentable, and censorship-shaped, because it can
|
|
9
|
+
* differ per node or per client version.
|
|
10
|
+
*
|
|
11
|
+
* THE PREIMAGE IS AN ARRAY, NOT A MAP, AND THAT IS LOAD-BEARING (M10-D15).
|
|
12
|
+
* The shared encoder (`cbor.ts`) is not RFC 8949 §4.2 deterministic for MAPS: map keys follow
|
|
13
|
+
* INSERTION ORDER, and map headers are not minimal-length (a 2-entry map emits `b9 0002`, not `a2`).
|
|
14
|
+
* Arrays, text strings, byte strings, integers and null are all minimal and order-fixed. Encoding
|
|
15
|
+
* the preimage as a fixed-order array therefore makes determinism STRUCTURAL — a property of the
|
|
16
|
+
* shape, not of the encoder's configuration — and costs no encoder change and no migration of the
|
|
17
|
+
* blobs already on disk. Every signed TBS in CELLO is an array for this same reason
|
|
18
|
+
* (`buildAgentRevocationTbs`, `buildPrimaryTransferTbs`, `buildSealTbs`, `buildParkContentTbs`).
|
|
19
|
+
*
|
|
20
|
+
* Consequences, all enforced below:
|
|
21
|
+
* - FIELD ORDER IS THE WIRE FORMAT. Reordering the array is a breaking hash change, not a
|
|
22
|
+
* refactor. Retrofitting a canonical form later breaks every hash already minted (spec §5).
|
|
23
|
+
* - THE FIELD SET IS CLOSED (spec §4). An unknown field is REJECTED, never ignored: silently
|
|
24
|
+
* dropping it would let two parties who disagree about the field set still agree on the hash,
|
|
25
|
+
* making the extra field unauthenticated data riding inside a "verified" signal.
|
|
26
|
+
* - `status` / `class` / `verified_at` ARE NOT IN THE PREIMAGE. They are mutable after minting —
|
|
27
|
+
* that is the entire point of excluding them. If `status` were hashed, revoking a signal would
|
|
28
|
+
* change its hash and the directory could never find it again.
|
|
29
|
+
* - OPTIONAL FIELDS ARE AN EXPLICIT `null` IN A FIXED SLOT, NEVER OMITTED (M10-D17). In an array,
|
|
30
|
+
* omitting a field shifts every later field and changes the arity, so an absent `expires_at`
|
|
31
|
+
* becomes confusable with a misaligned `supersedes_hash`.
|
|
32
|
+
* - NO FLOATING POINT. Timestamps are integer epoch SECONDS. A float would not survive
|
|
33
|
+
* byte-agreement across languages.
|
|
34
|
+
* - `payload` IS OPAQUE BYTES, never decoded or re-encoded. A payload parsed and re-serialized
|
|
35
|
+
* would change bytes under a different encoder version. This is also what INV-ZERO-BUMP rests
|
|
36
|
+
* on: a type this code has never seen must hash and flow through untouched.
|
|
37
|
+
*/
|
|
38
|
+
import { hash as sha256 } from "@cello-protocol/crypto";
|
|
39
|
+
import { encodeCbor, decodeCbor } from "./cbor.js";
|
|
40
|
+
/** Domain separation, bound as element 0 of the preimage array — the house convention
|
|
41
|
+
* (`AGENT_REVOCATION_DOMAIN`, `PRIMARY_TRANSFER_DOMAIN`). A trust-signal hash can therefore never
|
|
42
|
+
* collide with, or be replayed as, any other hashed/signed CELLO structure. */
|
|
43
|
+
export const TRUST_SIGNAL_DOMAIN = "CELLO-TSIG-v1";
|
|
44
|
+
/** The preimage field order. THIS ARRAY IS THE WIRE FORMAT — reordering it breaks every hash ever
|
|
45
|
+
* minted. It also doubles as the closed-set definition used to reject unknown fields. */
|
|
46
|
+
const PREIMAGE_FIELDS = [
|
|
47
|
+
"subject_kind",
|
|
48
|
+
"subject",
|
|
49
|
+
"issuer_kind",
|
|
50
|
+
"issuer_pubkey",
|
|
51
|
+
"type",
|
|
52
|
+
"schema_version",
|
|
53
|
+
"payload",
|
|
54
|
+
"issued_at",
|
|
55
|
+
"expires_at",
|
|
56
|
+
"supersedes_hash",
|
|
57
|
+
];
|
|
58
|
+
/** Sanity bound on epoch-SECOND timestamps. A millisecond timestamp (~1.7e12) is the classic
|
|
59
|
+
* cross-implementation skew: it is a valid integer, so nothing would complain, and it would mint a
|
|
60
|
+
* signal that expires roughly thirty thousand years from now. Refuse it at the door. */
|
|
61
|
+
const MAX_EPOCH_SECONDS = 100_000_000_000; // ~year 5138
|
|
62
|
+
/** Above this, a JS `number` is encoded by cbor-x as an IEEE **float64** (major type 7), not as a
|
|
63
|
+
* uint64 — see `asCborInteger`. Anything hashed must cross this boundary as a BigInt. */
|
|
64
|
+
const CBOR_UINT32_MAX = 0xffff_ffff;
|
|
65
|
+
/** SHA-256. Named separately from SUPERSEDES_HASH_BYTES even though both are 32 today: they are
|
|
66
|
+
* independent sizes, and coupling them means a future change to one silently breaks the other. */
|
|
67
|
+
const SIGNAL_HASH_BYTES = 32;
|
|
68
|
+
const SUPERSEDES_HASH_BYTES = 32;
|
|
69
|
+
/**
|
|
70
|
+
* Integers above 2³² MUST cross into CBOR as BigInt, or they are hashed as a FLOAT.
|
|
71
|
+
*
|
|
72
|
+
* Measured with this package's encoder:
|
|
73
|
+
*
|
|
74
|
+
* encode(1768000000) -> 1a 69618a00 uint32 (fine)
|
|
75
|
+
* encode(4920000000) -> fb 41f25413e0000000 FLOAT64 (WRONG)
|
|
76
|
+
* encode(BigInt(4920000000)) -> 1b 0000000125413e00 uint64 (what RFC 8949 requires)
|
|
77
|
+
*
|
|
78
|
+
* cbor-x emits any JS `number` above 0xffffffff as major type 7 float64. A conforming CBOR
|
|
79
|
+
* implementation in Rust, Go, or Python emits a uint64 — so the two disagree on the preimage, and
|
|
80
|
+
* therefore on the hash, permanently and unfixably (spec §5: retrofitting the canonical form breaks
|
|
81
|
+
* every hash already minted).
|
|
82
|
+
*
|
|
83
|
+
* This is NOT hypothetical and NOT a 2106 problem: an `expires_at` a hundred years out is
|
|
84
|
+
* 1.768e9 + 3.15e9 = 4.92e9, well past 2³², and reachable by the first long-dated signal the portal
|
|
85
|
+
* mints. `buildSealTbs` (session.ts) and `buildAgentRevocationTbs` (revocation.ts) both carry this
|
|
86
|
+
* coercion. The trust-signal envelope shipped without it and a reviewer caught it.
|
|
87
|
+
*/
|
|
88
|
+
function asCborInteger(value) {
|
|
89
|
+
return value > CBOR_UINT32_MAX ? BigInt(value) : value;
|
|
90
|
+
}
|
|
91
|
+
/** A non-negative integer safe to hash — rejected if it is a float, NaN, Infinity, or negative, and
|
|
92
|
+
* coerced to BigInt past 2³² so it never encodes as a float64. */
|
|
93
|
+
function requireHashableInteger(name, value, max, hint) {
|
|
94
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
95
|
+
throw new Error(`trust-signal envelope: ${name} must be a finite integer, got ${String(value)}`);
|
|
96
|
+
}
|
|
97
|
+
if (!Number.isInteger(value)) {
|
|
98
|
+
throw new Error(`trust-signal envelope: ${name} must be an integer — no floating point is hashable across implementations, got ${value}`);
|
|
99
|
+
}
|
|
100
|
+
if (value < 0) {
|
|
101
|
+
throw new Error(`trust-signal envelope: ${name} must not be negative, got ${value}`);
|
|
102
|
+
}
|
|
103
|
+
if (value > Number.MAX_SAFE_INTEGER) {
|
|
104
|
+
// Past 2^53 a JS number cannot even represent consecutive integers, so the value the caller
|
|
105
|
+
// meant and the value we hash may already differ. Refuse rather than hash an approximation.
|
|
106
|
+
throw new Error(`trust-signal envelope: ${name} exceeds Number.MAX_SAFE_INTEGER (${value}) — it cannot be hashed exactly`);
|
|
107
|
+
}
|
|
108
|
+
if (value >= max) {
|
|
109
|
+
throw new Error(`trust-signal envelope: ${name} is out of range (${value}) — ${hint}`);
|
|
110
|
+
}
|
|
111
|
+
return asCborInteger(value);
|
|
112
|
+
}
|
|
113
|
+
const requireEpochSeconds = (name, value) => requireHashableInteger(name, value, MAX_EPOCH_SECONDS, "this looks like a millisecond timestamp; the contract is epoch SECONDS");
|
|
114
|
+
/**
|
|
115
|
+
* Every hashed STRING must be NFC-normalized, and we REFUSE a string that is not — we never
|
|
116
|
+
* normalize it silently.
|
|
117
|
+
*
|
|
118
|
+
* Spec §5's list of cross-language hash-breakers names Unicode normalization explicitly. The same
|
|
119
|
+
* logical string differs on the wire: "é" is `62 c3a9` in NFC and `63 65cc81` in NFD. CBOR does not
|
|
120
|
+
* normalize, and RFC 8949's deterministic profile does not require NFC, so nothing downstream saves
|
|
121
|
+
* us.
|
|
122
|
+
*
|
|
123
|
+
* Refusing rather than normalizing is deliberate: silently normalizing would make two DIFFERENT
|
|
124
|
+
* inputs hash to the SAME signal — a collision we manufactured ourselves, which is strictly worse
|
|
125
|
+
* than refusing the odd one at the door.
|
|
126
|
+
*/
|
|
127
|
+
function requireNfcString(name, value) {
|
|
128
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
129
|
+
throw new Error(`trust-signal envelope: ${name} must be a non-empty string, got ${String(value)}`);
|
|
130
|
+
}
|
|
131
|
+
if (value.normalize("NFC") !== value) {
|
|
132
|
+
throw new Error(`trust-signal envelope: ${name} must be Unicode NFC-normalized — the same logical string hashes ` +
|
|
133
|
+
`differently in NFD ("é" is c3a9 in NFC, 65cc81 in NFD), so a non-NFC value would produce a ` +
|
|
134
|
+
`signal no other implementation can reproduce. Normalize it before minting.`);
|
|
135
|
+
}
|
|
136
|
+
return value;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Validate against the CLOSED preimage set and return the fixed-order array to encode.
|
|
140
|
+
*
|
|
141
|
+
* Every rejection here is deliberate and loud. An envelope that cannot be canonicalized must never
|
|
142
|
+
* be hashed "best effort" — a best-effort hash is a hash two parties can disagree about.
|
|
143
|
+
*/
|
|
144
|
+
function toPreimage(envelope) {
|
|
145
|
+
if (envelope === null || typeof envelope !== "object") {
|
|
146
|
+
throw new Error(`trust-signal envelope: expected an object, got ${String(envelope)}`);
|
|
147
|
+
}
|
|
148
|
+
// Closed set, both directions: no unknown fields, no missing fields.
|
|
149
|
+
const known = new Set(PREIMAGE_FIELDS);
|
|
150
|
+
for (const key of Object.keys(envelope)) {
|
|
151
|
+
if (!known.has(key)) {
|
|
152
|
+
throw new Error(`trust-signal envelope: unknown envelope field "${key}". The preimage is a CLOSED set (spec §4) — ` +
|
|
153
|
+
`an unhashed field riding inside a verified signal is unauthenticated data. ` +
|
|
154
|
+
`Note status/class/verified_at are deliberately NOT hashed (they are mutable after minting) ` +
|
|
155
|
+
`and do not belong on this object.`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
for (const field of PREIMAGE_FIELDS) {
|
|
159
|
+
if (!(field in envelope)) {
|
|
160
|
+
throw new Error(`trust-signal envelope: missing mandatory field "${field}" (the preimage is a closed set — spec §4)`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const { subject_kind, subject, issuer_kind, issuer_pubkey, type, schema_version, payload, expires_at, supersedes_hash } = envelope;
|
|
164
|
+
if (subject_kind !== "account" && subject_kind !== "agent") {
|
|
165
|
+
throw new Error(`trust-signal envelope: subject_kind must be "account" or "agent", got ${String(subject_kind)}`);
|
|
166
|
+
}
|
|
167
|
+
if (issuer_kind !== "portal" && issuer_kind !== "agent") {
|
|
168
|
+
throw new Error(`trust-signal envelope: issuer_kind must be "portal" or "agent", got ${String(issuer_kind)}`);
|
|
169
|
+
}
|
|
170
|
+
requireNfcString("subject", subject);
|
|
171
|
+
requireNfcString("type", type);
|
|
172
|
+
// issuer_pubkey is hex, and hex has a CASE. "AABB" and "aabb" are the same key and DIFFERENT bytes,
|
|
173
|
+
// so a portal that stores it uppercase and a directory that lowercases it on read would produce
|
|
174
|
+
// two different signal_hashes for one signal — a false hash_mismatch, per-node and per-version.
|
|
175
|
+
// Lowercase-only removes the ambiguity at zero cost. (Length/validity is NOT checked here: this
|
|
176
|
+
// component's job is byte-agreement, and the key's validity is the directory's to judge when it
|
|
177
|
+
// checks it against the authorized-issuer set.)
|
|
178
|
+
requireNfcString("issuer_pubkey", issuer_pubkey);
|
|
179
|
+
if (!/^[0-9a-f]+$/.test(issuer_pubkey) || issuer_pubkey.length % 2 !== 0) {
|
|
180
|
+
throw new Error(`trust-signal envelope: issuer_pubkey must be LOWERCASE hex with an even length, got "${issuer_pubkey}". ` +
|
|
181
|
+
`Hex has a case, and "AABB" and "aabb" are the same key but different preimage bytes — which would ` +
|
|
182
|
+
`mint two different hashes for one signal.`);
|
|
183
|
+
}
|
|
184
|
+
const schemaVersion = requireHashableInteger("schema_version", schema_version, CBOR_UINT32_MAX + 1, "a schema version is a small counter, not an identifier");
|
|
185
|
+
// The payload must be RAW BYTES. An object here would be encoded as a CBOR map — the one
|
|
186
|
+
// non-deterministic shape in the encoder — and the hash would silently depend on key insertion
|
|
187
|
+
// order. Callers serialize their own payload and hand us the bytes.
|
|
188
|
+
if (!(payload instanceof Uint8Array)) {
|
|
189
|
+
throw new Error(`trust-signal envelope: payload must be raw bytes (Uint8Array), got ${payload === null ? "null" : typeof payload}. ` +
|
|
190
|
+
`An object payload would be map-encoded, and CBOR maps are not deterministic under this encoder — ` +
|
|
191
|
+
`serialize the payload yourself and pass the bytes.`);
|
|
192
|
+
}
|
|
193
|
+
const issuedAt = requireEpochSeconds("issued_at", envelope.issued_at);
|
|
194
|
+
const expiresAt = expires_at === null ? null : requireEpochSeconds("expires_at", expires_at);
|
|
195
|
+
if (supersedes_hash !== null) {
|
|
196
|
+
if (!(supersedes_hash instanceof Uint8Array)) {
|
|
197
|
+
throw new Error(`trust-signal envelope: supersedes_hash must be 32 raw bytes or null, got ${typeof supersedes_hash}`);
|
|
198
|
+
}
|
|
199
|
+
if (supersedes_hash.length !== SUPERSEDES_HASH_BYTES) {
|
|
200
|
+
throw new Error(`trust-signal envelope: supersedes_hash must be exactly ${SUPERSEDES_HASH_BYTES} bytes, got ${supersedes_hash.length}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// FIXED ORDER. Element 0 is the domain tag; the nullable slots keep their position so arity is
|
|
204
|
+
// always 11 and no field can be mistaken for another (M10-D17).
|
|
205
|
+
return [
|
|
206
|
+
TRUST_SIGNAL_DOMAIN,
|
|
207
|
+
subject_kind,
|
|
208
|
+
subject,
|
|
209
|
+
issuer_kind,
|
|
210
|
+
issuer_pubkey,
|
|
211
|
+
type,
|
|
212
|
+
schemaVersion,
|
|
213
|
+
payload,
|
|
214
|
+
issuedAt,
|
|
215
|
+
expiresAt,
|
|
216
|
+
supersedes_hash,
|
|
217
|
+
];
|
|
218
|
+
}
|
|
219
|
+
/** The canonical preimage bytes. Deterministic across every party that runs this code. */
|
|
220
|
+
export function encodeTrustSignalEnvelope(envelope) {
|
|
221
|
+
return encodeCbor(toPreimage(envelope));
|
|
222
|
+
}
|
|
223
|
+
/** The signal's identity: SHA-256 over the canonical preimage. This is the `signal_hash` that the
|
|
224
|
+
* directory stores, the holder presents, and the recipient re-derives. */
|
|
225
|
+
export function hashTrustSignalEnvelope(envelope) {
|
|
226
|
+
return sha256(encodeTrustSignalEnvelope(envelope));
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Does this envelope actually hash to `expected`? Length is checked first, so a truncated hash can
|
|
230
|
+
* never pass by matching a prefix. The comparison is constant-time in the length of the input: a
|
|
231
|
+
* signal hash is public, but the habit is cheap and the alternative invites a timing oracle the day
|
|
232
|
+
* one of these stops being public.
|
|
233
|
+
*
|
|
234
|
+
* ⚠️ THIS RETURNS `false` FOR A WRONG HASH BUT **THROWS** FOR A MALFORMED ENVELOPE, AND THAT
|
|
235
|
+
* ASYMMETRY IS DELIBERATE. A wrong hash is a normal, expected answer ("no, this doesn't match"). A
|
|
236
|
+
* malformed envelope is not an answer at all — it is an envelope that cannot be canonicalized, so
|
|
237
|
+
* there is no hash to compare and any boolean would be a lie.
|
|
238
|
+
*
|
|
239
|
+
* The directory calls this on hostile input. DO NOT wrap it in `try { … } catch { return false }`:
|
|
240
|
+
* that converts "this envelope is unhashable garbage" into "this envelope simply didn't match",
|
|
241
|
+
* which is the silent swallow that hides the attack. Let it throw, and log the cause.
|
|
242
|
+
*/
|
|
243
|
+
export function verifyTrustSignalHash(envelope, expected) {
|
|
244
|
+
if (!(expected instanceof Uint8Array) || expected.length !== SIGNAL_HASH_BYTES)
|
|
245
|
+
return false;
|
|
246
|
+
const actual = hashTrustSignalEnvelope(envelope);
|
|
247
|
+
let diff = 0;
|
|
248
|
+
for (let i = 0; i < actual.length; i++)
|
|
249
|
+
diff |= actual[i] ^ expected[i];
|
|
250
|
+
return diff === 0;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Decode canonical envelope bytes back into the envelope — the inverse of `encodeTrustSignalEnvelope`,
|
|
254
|
+
* and the ONE decoder every party shares (INV-CANONICAL / M10-D7 — the holder's daemon that RECEIVES a
|
|
255
|
+
* delivered signal must decode with the SAME code the directory and portal encode with, never a vendored
|
|
256
|
+
* copy). The preimage is a fixed-order 11-element ARRAY (M10-D15); element 0 is the domain tag.
|
|
257
|
+
*
|
|
258
|
+
* REFUSES anything that is not EXACTLY canonical: it re-encodes the decoded envelope with
|
|
259
|
+
* `encodeTrustSignalEnvelope` and compares the bytes to the input. If they differ — a number that came
|
|
260
|
+
* back as a float, a byte string mis-read, a non-minimal integer, trailing bytes — it THROWS rather than
|
|
261
|
+
* return a "best-effort" envelope: a best-effort hash is one two parties can disagree about. Reusing the
|
|
262
|
+
* encoder (not a hand-rolled re-encode) guarantees the decoder cannot drift from it, AND runs the encoder's
|
|
263
|
+
* own field validation (epoch-seconds bounds, payload-is-bytes, 32-byte supersedes_hash) — so a
|
|
264
|
+
* canonical-at-the-byte-level-but-semantically-invalid array (e.g. an out-of-range subject_kind) still
|
|
265
|
+
* throws here rather than escaping as a bad envelope.
|
|
266
|
+
*
|
|
267
|
+
* ⚠️ THROWS on any malformed/non-canonical input (never returns a partial). The holder's chokepoint
|
|
268
|
+
* (`deliverWalletSignal`) and the recipient's verify both depend on that: a delivery that does not
|
|
269
|
+
* round-trip is corrupt or tampered and must not be stored. Do NOT wrap in try/catch → default — that is
|
|
270
|
+
* the silent swallow that turns "unhashable garbage" into "a valid-looking empty signal".
|
|
271
|
+
*/
|
|
272
|
+
export function decodeTrustSignalEnvelope(bytes) {
|
|
273
|
+
const arr = decodeCbor(bytes);
|
|
274
|
+
if (!Array.isArray(arr) || arr.length !== 11) {
|
|
275
|
+
throw new Error(`trust-signal envelope must be an 11-element CBOR array (the fixed preimage), got ` +
|
|
276
|
+
`${Array.isArray(arr) ? `${arr.length} elements` : typeof arr}`);
|
|
277
|
+
}
|
|
278
|
+
const [domain, subject_kind, subject, issuer_kind, issuer_pubkey, type, schema_version, payload, issued_at, expires_at, supersedes_hash] = arr;
|
|
279
|
+
if (domain !== TRUST_SIGNAL_DOMAIN) {
|
|
280
|
+
throw new Error(`trust-signal envelope domain tag is '${String(domain)}', expected '${TRUST_SIGNAL_DOMAIN}' — not a trust-signal envelope`);
|
|
281
|
+
}
|
|
282
|
+
// NORMALIZE to a plain, freshly-copied Uint8Array. node's CBOR decoder returns byte strings as a
|
|
283
|
+
// `Buffer` (a Uint8Array subclass) that can ALIAS a pooled ArrayBuffer — returning it as-is would leak a
|
|
284
|
+
// view over shared memory and make the decoded type Buffer, not Uint8Array. `new Uint8Array(v)` copies
|
|
285
|
+
// the bytes into an owned array, so the envelope's byte fields are the same type the encoder expects and
|
|
286
|
+
// never alias a pool.
|
|
287
|
+
const asBytes = (v, field) => {
|
|
288
|
+
if (v instanceof Uint8Array)
|
|
289
|
+
return new Uint8Array(v);
|
|
290
|
+
throw new Error(`trust-signal envelope: ${field} must be raw bytes, got ${v === null ? "null" : typeof v}`);
|
|
291
|
+
};
|
|
292
|
+
const env = {
|
|
293
|
+
subject_kind: subject_kind,
|
|
294
|
+
subject: subject,
|
|
295
|
+
issuer_kind: issuer_kind,
|
|
296
|
+
issuer_pubkey: issuer_pubkey,
|
|
297
|
+
type: type,
|
|
298
|
+
schema_version: Number(schema_version),
|
|
299
|
+
payload: asBytes(payload, "payload"),
|
|
300
|
+
issued_at: Number(issued_at),
|
|
301
|
+
expires_at: expires_at === null || expires_at === undefined ? null : Number(expires_at),
|
|
302
|
+
supersedes_hash: supersedes_hash === null || supersedes_hash === undefined ? null : asBytes(supersedes_hash, "supersedes_hash"),
|
|
303
|
+
};
|
|
304
|
+
// Canonical check: re-encode with the SAME encoder every party runs and compare EXACTLY.
|
|
305
|
+
const reencoded = encodeTrustSignalEnvelope(env);
|
|
306
|
+
if (reencoded.length !== bytes.length) {
|
|
307
|
+
throw new Error("trust-signal envelope bytes are not canonical — re-encoding does not reproduce the input");
|
|
308
|
+
}
|
|
309
|
+
for (let i = 0; i < reencoded.length; i++) {
|
|
310
|
+
if (reencoded[i] !== bytes[i]) {
|
|
311
|
+
throw new Error("trust-signal envelope bytes are not canonical — re-encoding does not reproduce the input");
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return env;
|
|
315
|
+
}
|
|
316
|
+
//# sourceMappingURL=trust-signal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust-signal.js","sourceRoot":"","sources":["../src/trust-signal.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cello-protocol/protocol-types",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -15,15 +15,18 @@
|
|
|
15
15
|
".": {
|
|
16
16
|
"import": "./dist/index.js",
|
|
17
17
|
"types": "./dist/index.d.ts"
|
|
18
|
-
}
|
|
18
|
+
},
|
|
19
|
+
"./test/vectors/*": "./test/vectors/*",
|
|
20
|
+
"./package.json": "./package.json"
|
|
19
21
|
},
|
|
20
22
|
"files": [
|
|
21
23
|
"dist/",
|
|
24
|
+
"test/vectors/",
|
|
22
25
|
"package.json"
|
|
23
26
|
],
|
|
24
27
|
"dependencies": {
|
|
25
28
|
"cbor-x": "^1.6.4",
|
|
26
|
-
"@cello-protocol/crypto": "0.0.
|
|
29
|
+
"@cello-protocol/crypto": "0.0.22"
|
|
27
30
|
},
|
|
28
31
|
"devDependencies": {
|
|
29
32
|
"@claude-flow/testing": "3.0.0-alpha.6",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "CELLO-CONNREQ-001: connection package canonical CBOR fixture",
|
|
3
|
+
"seed_hex": "deadbeefcafe0102030405060708090a0b0c0d0e0f101112131415161718191a",
|
|
4
|
+
"pseudonym_label": "ac009-agent",
|
|
5
|
+
"klocal_pubkey_derive": "ac009-klocal",
|
|
6
|
+
"primary_pubkey_derive": "ac009-primary",
|
|
7
|
+
"created_at": 1746057600000,
|
|
8
|
+
"expected_cbor_hex": "b900037170736575646f6e796d5f62696e64696e67b900066f70736575646f6e796d5f6c6162656c6b61633030392d6167656e746e6b5f6c6f63616c5f7075626b657958204c4dc1cdb4434b1cf0efc479f57f71c3e095ca28835ebf0fdd295fe48b6247916e7072696d6172795f7075626b657958409a8f5157d02c2588c6468da9e74b8414fe3719cd254de95689a045e01afa3bf69a8f5157d02c2588c6468da9e74b8414fe3719cd254de95689a045e01afa3bf66d6d6c5f6473615f7075626b65795905202e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad2e329a65af7790d0d9374d4893a5d5dcbab74f3c5b9f4cfe5788d57fb58273ad6a637265617465645f61741b0000019689249c00706d6c5f6473615f7369676e617475726559097494de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d60830a5d0f5bf7021ab000caf8a6994de5f68123bf5f8eaaf206a1daf32fa13d608306c656e646f7273656d656e7473806c6174746573746174696f6e7380",
|
|
9
|
+
"_encoding": "Plain CBOR (RFC 8949). Byte fields are CBOR byte strings; objects are CBOR maps. NOT cbor-x's record extension (tag 57343) \u2014 that is a cbor-x-private format no other CBOR reader can parse."
|
|
10
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "CELLO-MSG-003 AC-007 canonical v1 envelope fixture. Cross-implementation regression guard. RFC 8949 §4.2.1.",
|
|
3
|
+
"_note": "full_envelope_cbor_hex excludes sender_signature (keypair-dependent). Tests verify tbs_cbor_hex and content_hash_hex; signature is tested separately with a generated keypair.",
|
|
4
|
+
"inputs": {
|
|
5
|
+
"protocol_version": 1,
|
|
6
|
+
"content_hex": "68656c6c6f",
|
|
7
|
+
"sender_pubkey_hex": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
8
|
+
"session_id_hex": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
9
|
+
"last_seen_seq": 0,
|
|
10
|
+
"timestamp": 1700000000000
|
|
11
|
+
},
|
|
12
|
+
"expected": {
|
|
13
|
+
"content_hash_hex": "8a2a5c9b768827de5a9552c38a044c66959c68f6d2f21b5260af54d2f87db827",
|
|
14
|
+
"tbs_cbor_hex": "860158208a2a5c9b768827de5a9552c38a044c66959c68f6d2f21b5260af54d2f87db8275820aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa50bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb001b0000018bcfe56800"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "CELLO-SESSION-002 SI-004: genesis prev_root fixture. SHA-256(min(A,B) || max(A,B) || session_id || session_timestamp_be8) where pubkeys are sorted bytewise-lexicographically and timestamp is 8-byte big-endian unsigned integer (milliseconds since Unix epoch).",
|
|
3
|
+
"fixtures": [
|
|
4
|
+
{
|
|
5
|
+
"_note": "A < B (0xaa < 0xbb) — no reordering needed",
|
|
6
|
+
"inputs": {
|
|
7
|
+
"pubkey_a_hex": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
8
|
+
"pubkey_b_hex": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
9
|
+
"session_id_hex": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
|
10
|
+
"session_timestamp_ms": 1700000000000
|
|
11
|
+
},
|
|
12
|
+
"intermediate": {
|
|
13
|
+
"min_pubkey_hex": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
14
|
+
"max_pubkey_hex": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
15
|
+
"timestamp_be8_hex": "0000018bcfe56800",
|
|
16
|
+
"preimage_hex": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000018bcfe56800"
|
|
17
|
+
},
|
|
18
|
+
"expected_genesis_prev_root_hex": "e2f3e8e2eff39907ea59df96aa4f63dbdae3ca8cebe35ed5e5240b1543161932"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"_note": "B < A (0xaa < 0xbb) — args supplied in reversed order; result must be identical to fixture 1 with same effective min/max",
|
|
22
|
+
"inputs": {
|
|
23
|
+
"pubkey_a_hex": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
24
|
+
"pubkey_b_hex": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
25
|
+
"session_id_hex": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
|
26
|
+
"session_timestamp_ms": 1700000000000
|
|
27
|
+
},
|
|
28
|
+
"intermediate": {
|
|
29
|
+
"min_pubkey_hex": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
30
|
+
"max_pubkey_hex": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
31
|
+
"timestamp_be8_hex": "0000018bcfe56800",
|
|
32
|
+
"preimage_hex": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000018bcfe56800"
|
|
33
|
+
},
|
|
34
|
+
"expected_genesis_prev_root_hex": "e2f3e8e2eff39907ea59df96aa4f63dbdae3ca8cebe35ed5e5240b1543161932"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"_note": "Different pubkeys and timestamp — cross-check for distinct inputs",
|
|
38
|
+
"inputs": {
|
|
39
|
+
"pubkey_a_hex": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
40
|
+
"pubkey_b_hex": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
41
|
+
"session_id_hex": "11111111111111111111111111111111",
|
|
42
|
+
"session_timestamp_ms": 1746000000000
|
|
43
|
+
},
|
|
44
|
+
"intermediate": {
|
|
45
|
+
"min_pubkey_hex": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
46
|
+
"max_pubkey_hex": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
47
|
+
"timestamp_be8_hex": "0000019685b5b400",
|
|
48
|
+
"preimage_hex": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb111111111111111111111111111111110000019685b5b400"
|
|
49
|
+
},
|
|
50
|
+
"expected_genesis_prev_root_hex": "b78b94839803ec7f1654518c0fbb796f1ba2992f7f40d611cca7948b92ff2848"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "CELLO-MERKLE-002 AC-007: M1 scan_result sentinel — canonical CBOR map. RFC 8949 §4.2.1.",
|
|
3
|
+
"_note": "CBOR map with 3 keys sorted by byte-length (RFC 8949 §4.2.1): score(5) < verdict(7) < model_hash(10). score=null, verdict='unscanned' (9 bytes), model_hash=<32 zero bytes>.",
|
|
4
|
+
"expected_cbor_hex": "a36573636f7265f6677665726469637469756e7363616e6e65646a6d6f64656c5f6861736858200000000000000000000000000000000000000000000000000000000000000000"
|
|
5
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "CELLO-MERKLE-002 AC-001: Structure 1 canonical CBOR fixture. RFC 8949 §4.2.1.",
|
|
3
|
+
"_note": "Canonical CBOR of the 6-element positional TBS array for protocol_version=1.",
|
|
4
|
+
"inputs": {
|
|
5
|
+
"protocol_version": 1,
|
|
6
|
+
"content_hash_hex": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
|
|
7
|
+
"sender_pubkey_hex": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
|
8
|
+
"session_id_hex": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
|
9
|
+
"last_seen_seq": 3,
|
|
10
|
+
"timestamp": 1700000000000
|
|
11
|
+
},
|
|
12
|
+
"expected_cbor_hex": "86015820cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc5820dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd50eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee031b0000018bcfe56800"
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "CELLO-MERKLE-002 AC-002: Structure 2 canonical CBOR fixture. RFC 8949 §4.2.1.",
|
|
3
|
+
"_note": "Canonical CBOR of the 6-element positional relay-built leaf: [sequence_number, sender_pubkey, content_hash, sender_signature, scan_result, prev_root]. scan_result is the M1 sentinel: {score:null, verdict:'unscanned', model_hash:<32 zero bytes>}.",
|
|
4
|
+
"inputs": {
|
|
5
|
+
"sequence_number": 1,
|
|
6
|
+
"sender_pubkey_hex": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
|
7
|
+
"content_hash_hex": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
|
|
8
|
+
"sender_signature_hex": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
9
|
+
"prev_root_hex": "0000000000000000000000000000000000000000000000000000000000000000"
|
|
10
|
+
},
|
|
11
|
+
"expected_cbor_hex": "86015820dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd5820cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc5840aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa36573636f7265f6677665726469637469756e7363616e6e65646a6d6f64656c5f686173685820000000000000000000000000000000000000000000000000000000000000000058200000000000000000000000000000000000000000000000000000000000000000"
|
|
12
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "CELLO-MSG-001 TBS v0 canonical CBOR fixture. Cross-implementation regression guard. RFC 8949 \u00a74.2.1.",
|
|
3
|
+
"protocol_version": 0,
|
|
4
|
+
"content_hash_hex": "0000000000000000000000000000000000000000000000000000000000000000",
|
|
5
|
+
"sender_pubkey_hex": "abababababababababababababababababababababababababababababababab",
|
|
6
|
+
"timestamp": 1746057600000,
|
|
7
|
+
"expected_cbor_hex": "8400582000000000000000000000000000000000000000000000000000000000000000005820abababababababababababababababababababababababababababababababab1b0000019689249c00"
|
|
8
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": [
|
|
3
|
+
"DOD-CBOR-1 / DOD-INV-CANONICAL — FROZEN cross-party vectors for the trust-signal envelope.",
|
|
4
|
+
"Every party that derives a signal_hash — the portal at mint, the directory at submission and at",
|
|
5
|
+
"presentation, the holder and recipient daemons — MUST reproduce these bytes exactly. All three",
|
|
6
|
+
"repos check their SHIPPED @cello-protocol/protocol-types against this file, so a version skew",
|
|
7
|
+
"between repos fails loud here instead of silently forking the hash in production.",
|
|
8
|
+
"Preimage (array, fixed order, domain tag in slot 0 — M10-D15/D17):",
|
|
9
|
+
" [ 'CELLO-TSIG-v1', subject_kind, subject, issuer_kind, issuer_pubkey, type, schema_version,",
|
|
10
|
+
" payload, issued_at, expires_at|null, supersedes_hash|null ]",
|
|
11
|
+
"payload and supersedes_hash are hex-encoded HERE for legibility only; they are RAW BYTES in the",
|
|
12
|
+
"preimage. status/class/verified_at are deliberately NOT hashed (mutable after minting).",
|
|
13
|
+
"CHANGING A BYTE IN THIS FILE IS A PROTOCOL BREAK — it invalidates every signal ever minted."
|
|
14
|
+
],
|
|
15
|
+
"vectors": [
|
|
16
|
+
{
|
|
17
|
+
"name": "reference — agent subject, portal issuer, no expiry, first mint",
|
|
18
|
+
"envelope": {
|
|
19
|
+
"subject_kind": "agent",
|
|
20
|
+
"subject": "agent-1",
|
|
21
|
+
"issuer_kind": "portal",
|
|
22
|
+
"issuer_pubkey": "aabb",
|
|
23
|
+
"type": "phone",
|
|
24
|
+
"schema_version": 1,
|
|
25
|
+
"payload": "01020304",
|
|
26
|
+
"issued_at": 1000000000,
|
|
27
|
+
"expires_at": null,
|
|
28
|
+
"supersedes_hash": null
|
|
29
|
+
},
|
|
30
|
+
"preimage_hex": "8b6d43454c4c4f2d545349472d7631656167656e74676167656e742d3166706f7274616c64616162626570686f6e650144010203041a3b9aca00f6f6",
|
|
31
|
+
"signal_hash_hex": "760af64a292f96bffde522e21a8fcae0c31fc7826c4e2c947939a2da50803672"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "account subject — one envelope, every agent under the account presents it (M10-D5)",
|
|
35
|
+
"envelope": {
|
|
36
|
+
"subject_kind": "account",
|
|
37
|
+
"subject": "acct_7f3a",
|
|
38
|
+
"issuer_kind": "portal",
|
|
39
|
+
"issuer_pubkey": "3d4f6a2b8c1e",
|
|
40
|
+
"type": "email",
|
|
41
|
+
"schema_version": 1,
|
|
42
|
+
"payload": "a1646b696e64",
|
|
43
|
+
"issued_at": 1768000000,
|
|
44
|
+
"expires_at": 1799536000,
|
|
45
|
+
"supersedes_hash": null
|
|
46
|
+
},
|
|
47
|
+
"preimage_hex": "8b6d43454c4c4f2d545349472d7631676163636f756e7469616363745f3766336166706f7274616c6c33643466366132623863316565656d61696c0146a1646b696e641a69618a001a6b42bd80f6",
|
|
48
|
+
"signal_hash_hex": "2b7ace095f07efbd1c8f5efef701a8969d2c6c8efb3f6291b27eefcd287fba16"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "supersession — a re-minted track-record signal replacing an earlier one",
|
|
52
|
+
"envelope": {
|
|
53
|
+
"subject_kind": "agent",
|
|
54
|
+
"subject": "agent-1",
|
|
55
|
+
"issuer_kind": "portal",
|
|
56
|
+
"issuer_pubkey": "aabb",
|
|
57
|
+
"type": "session_count",
|
|
58
|
+
"schema_version": 2,
|
|
59
|
+
"payload": "deadbeef",
|
|
60
|
+
"issued_at": 1768000123,
|
|
61
|
+
"expires_at": 1768604923,
|
|
62
|
+
"supersedes_hash": "1111111111111111111111111111111111111111111111111111111111111111"
|
|
63
|
+
},
|
|
64
|
+
"preimage_hex": "8b6d43454c4c4f2d545349472d7631656167656e74676167656e742d3166706f7274616c64616162626d73657373696f6e5f636f756e740244deadbeef1a69618a7b1a696ac4fb58201111111111111111111111111111111111111111111111111111111111111111",
|
|
65
|
+
"signal_hash_hex": "0184ae76433d9c4caf892d438bff3f64d44f0eed57470f0c141fee86b18e0bbb"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "agent issuer — quoted-untrusted framing at the LLM (INV-FRAMING)",
|
|
69
|
+
"envelope": {
|
|
70
|
+
"subject_kind": "agent",
|
|
71
|
+
"subject": "agent-2",
|
|
72
|
+
"issuer_kind": "agent",
|
|
73
|
+
"issuer_pubkey": "ff00ff00",
|
|
74
|
+
"type": "endorsement",
|
|
75
|
+
"schema_version": 1,
|
|
76
|
+
"payload": "",
|
|
77
|
+
"issued_at": 1768000000,
|
|
78
|
+
"expires_at": null,
|
|
79
|
+
"supersedes_hash": null
|
|
80
|
+
},
|
|
81
|
+
"preimage_hex": "8b6d43454c4c4f2d545349472d7631656167656e74676167656e742d32656167656e746866663030666630306b656e646f7273656d656e7401401a69618a00f6f6",
|
|
82
|
+
"signal_hash_hex": "39d148391745fa3ea26b8fe57b5633c4bec7064a896527abb9300355b02ec5a6"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "UNKNOWN type — a type this code has never seen must hash identically (INV-TYPE-CARRY)",
|
|
86
|
+
"envelope": {
|
|
87
|
+
"subject_kind": "agent",
|
|
88
|
+
"subject": "agent-1",
|
|
89
|
+
"issuer_kind": "portal",
|
|
90
|
+
"issuer_pubkey": "aabb",
|
|
91
|
+
"type": "some_type_invented_next_year",
|
|
92
|
+
"schema_version": 1,
|
|
93
|
+
"payload": "00",
|
|
94
|
+
"issued_at": 1768000000,
|
|
95
|
+
"expires_at": null,
|
|
96
|
+
"supersedes_hash": null
|
|
97
|
+
},
|
|
98
|
+
"preimage_hex": "8b6d43454c4c4f2d545349472d7631656167656e74676167656e742d3166706f7274616c6461616262781c736f6d655f747970655f696e76656e7465645f6e6578745f796561720141001a69618a00f6f6",
|
|
99
|
+
"signal_hash_hex": "9a637f2ca5b4fbb0f78c9eb2d33cfc433706290a7c4a4e6bf2628d258b90f1c9"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"name": "payload that LOOKS like CBOR — embedded verbatim, never parsed",
|
|
103
|
+
"envelope": {
|
|
104
|
+
"subject_kind": "agent",
|
|
105
|
+
"subject": "agent-1",
|
|
106
|
+
"issuer_kind": "portal",
|
|
107
|
+
"issuer_pubkey": "aabb",
|
|
108
|
+
"type": "canary_test",
|
|
109
|
+
"schema_version": 1,
|
|
110
|
+
"payload": "d840009fff",
|
|
111
|
+
"issued_at": 1768000000,
|
|
112
|
+
"expires_at": null,
|
|
113
|
+
"supersedes_hash": null
|
|
114
|
+
},
|
|
115
|
+
"preimage_hex": "8b6d43454c4c4f2d545349472d7631656167656e74676167656e742d3166706f7274616c64616162626b63616e6172795f746573740145d840009fff1a69618a00f6f6",
|
|
116
|
+
"signal_hash_hex": "5dc67366d7b8fc515a6d638b432d90e29a2f9841101a3ac1745ca7b602e2f837"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"name": "FAR-FUTURE expiry past 2^32 — must hash as a CBOR uint64 (1b...), NEVER a float64 (fb...)",
|
|
120
|
+
"envelope": {
|
|
121
|
+
"subject_kind": "agent",
|
|
122
|
+
"subject": "agent-1",
|
|
123
|
+
"issuer_kind": "portal",
|
|
124
|
+
"issuer_pubkey": "aabb",
|
|
125
|
+
"type": "phone",
|
|
126
|
+
"schema_version": 1,
|
|
127
|
+
"payload": "01020304",
|
|
128
|
+
"issued_at": 1768000000,
|
|
129
|
+
"expires_at": 4920000000,
|
|
130
|
+
"supersedes_hash": null
|
|
131
|
+
},
|
|
132
|
+
"preimage_hex": "8b6d43454c4c4f2d545349472d7631656167656e74676167656e742d3166706f7274616c64616162626570686f6e650144010203041a69618a001b0000000125413e00f6",
|
|
133
|
+
"signal_hash_hex": "3c95520077ca1bb25f360c886008691bab1114e1ecad43ba90558df5d5a0b79e"
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|