@synoi/sraid 0.2.0

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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/PROJECTION_SPEC.md +245 -0
  3. package/README.md +149 -0
  4. package/SPEC.md +216 -0
  5. package/dist/attestation.d.ts +92 -0
  6. package/dist/attestation.d.ts.map +1 -0
  7. package/dist/attestation.js +155 -0
  8. package/dist/attestation.js.map +1 -0
  9. package/dist/authority.d.ts +351 -0
  10. package/dist/authority.d.ts.map +1 -0
  11. package/dist/authority.js +563 -0
  12. package/dist/authority.js.map +1 -0
  13. package/dist/canonicalize.d.ts +70 -0
  14. package/dist/canonicalize.d.ts.map +1 -0
  15. package/dist/canonicalize.js +151 -0
  16. package/dist/canonicalize.js.map +1 -0
  17. package/dist/ed25519.d.ts +26 -0
  18. package/dist/ed25519.d.ts.map +1 -0
  19. package/dist/ed25519.js +53 -0
  20. package/dist/ed25519.js.map +1 -0
  21. package/dist/index.d.ts +28 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +46 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/internal/base64.d.ts +28 -0
  26. package/dist/internal/base64.d.ts.map +1 -0
  27. package/dist/internal/base64.js +45 -0
  28. package/dist/internal/base64.js.map +1 -0
  29. package/dist/internal/key-cache.d.ts +47 -0
  30. package/dist/internal/key-cache.d.ts.map +1 -0
  31. package/dist/internal/key-cache.js +77 -0
  32. package/dist/internal/key-cache.js.map +1 -0
  33. package/dist/lineage.d.ts +104 -0
  34. package/dist/lineage.d.ts.map +1 -0
  35. package/dist/lineage.js +0 -0
  36. package/dist/lineage.js.map +1 -0
  37. package/dist/mldsa.d.ts +41 -0
  38. package/dist/mldsa.d.ts.map +1 -0
  39. package/dist/mldsa.js +119 -0
  40. package/dist/mldsa.js.map +1 -0
  41. package/dist/oid.d.ts +109 -0
  42. package/dist/oid.d.ts.map +1 -0
  43. package/dist/oid.js +140 -0
  44. package/dist/oid.js.map +1 -0
  45. package/dist/sensitivity.d.ts +104 -0
  46. package/dist/sensitivity.d.ts.map +1 -0
  47. package/dist/sensitivity.js +117 -0
  48. package/dist/sensitivity.js.map +1 -0
  49. package/dist/signature.d.ts +46 -0
  50. package/dist/signature.d.ts.map +1 -0
  51. package/dist/signature.js +89 -0
  52. package/dist/signature.js.map +1 -0
  53. package/dist/types.d.ts +313 -0
  54. package/dist/types.d.ts.map +1 -0
  55. package/dist/types.js +16 -0
  56. package/dist/types.js.map +1 -0
  57. package/dist/validate.d.ts +88 -0
  58. package/dist/validate.d.ts.map +1 -0
  59. package/dist/validate.js +339 -0
  60. package/dist/validate.js.map +1 -0
  61. package/package.json +69 -0
  62. package/src/attestation.ts +204 -0
  63. package/src/authority.ts +849 -0
  64. package/src/canonicalize.ts +167 -0
  65. package/src/ed25519.ts +60 -0
  66. package/src/index.ts +118 -0
  67. package/src/internal/base64.ts +44 -0
  68. package/src/internal/key-cache.ts +79 -0
  69. package/src/lineage.ts +0 -0
  70. package/src/mldsa.ts +131 -0
  71. package/src/oid.ts +146 -0
  72. package/src/sensitivity.ts +154 -0
  73. package/src/signature.ts +119 -0
  74. package/src/types.ts +351 -0
  75. package/src/validate.ts +402 -0
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @synoi/sraid — attestation.ts
3
+ *
4
+ * L2 attestation layer: a DSSE (Dead Simple Signing Envelope) profile that
5
+ * carries one or more detached signatures over a SRAID object's canonical
6
+ * payload, with the payload TYPE structurally bound into the signed bytes.
7
+ *
8
+ * Why this exists (SRAID F7 / Adversary A4, SRAID_FOUNDATION_PUNCHLIST A3,
9
+ * OBJECT_MODEL_CLEANSHEET §3.2): the legacy `SignatureEnvelope` signs the
10
+ * bare canonical bytes with NO payload-type binding. Because every SRAID
11
+ * object shape (decision receipt, capability grant, memory record, identity
12
+ * disclosure, supply-chain attestation, …) is signed identically over its
13
+ * canonical bytes, a signature minted for one type could be replayed as a
14
+ * valid signature for a different type whose canonical bytes happen to match
15
+ * — a cross-type / confused-deputy hazard. DSSE closes this by signing the
16
+ * Pre-Authentication Encoding (PAE), which prepends the payloadType and the
17
+ * lengths of both fields, so the type is part of what is signed.
18
+ *
19
+ * SynOI policy (the AND rule): a SRAID attestation MUST carry BOTH an
20
+ * `ed25519` and an `ml-dsa-65` signature over the SAME PAE, and the verifier
21
+ * here requires BOTH to verify before returning `valid: true`. DSSE itself
22
+ * is an OR-of-signatures envelope; the both-required rule lives in this
23
+ * verifier and in the SRAID spec, not in DSSE. This preserves the hybrid
24
+ * classical + post-quantum property of the legacy scheme.
25
+ *
26
+ * Profile: JSON (`payloadType` is a media type string; `payload` is the
27
+ * canonical UTF-8 string). A future CBOR profile would use COSE (RFC 9052);
28
+ * it is reserved, not implemented here.
29
+ *
30
+ * Identity stability: signatures live in a detached `signatures[]` array and
31
+ * are NEVER part of the OID hash input (see `cdroContentCore` in oid.ts), so
32
+ * adding, rotating, or replacing a signature never changes the object's OID.
33
+ */
34
+ import type { AttestationEnvelope } from './types.js';
35
+ /** The single supported algorithm identifiers for the JSON profile. */
36
+ export declare const ALG_ED25519 = "ed25519";
37
+ export declare const ALG_ML_DSA_65 = "ml-dsa-65";
38
+ /**
39
+ * The DSSE Pre-Authentication Encoding (PAE).
40
+ *
41
+ * Per the DSSE spec:
42
+ *
43
+ * PAE(type, body) = "DSSEv1" SP LEN(type) SP type SP LEN(body) SP body
44
+ *
45
+ * where:
46
+ * - SP is a single ASCII space (0x20),
47
+ * - LEN(x) is the ASCII-decimal byte length of x's UTF-8 encoding,
48
+ * - type and body are the raw UTF-8 bytes (NOT base64).
49
+ *
50
+ * Binding the payloadType (and both lengths) into the signed bytes is what
51
+ * makes a signature non-transferable across object types. Returns the raw
52
+ * bytes to be signed/verified.
53
+ */
54
+ export declare function pae(payloadType: string, payload: string | Uint8Array): Uint8Array;
55
+ export interface VerifyAttestationInput {
56
+ /**
57
+ * The DSSE attestation envelope to verify. Its `payloadType` is bound into
58
+ * the PAE; its `payload` is the canonical UTF-8 string that was signed.
59
+ */
60
+ envelope: AttestationEnvelope;
61
+ /** Raw 32-byte Ed25519 public key. */
62
+ ed25519_pub: Uint8Array;
63
+ /** Raw ML-DSA-65 public key bytes. */
64
+ ml_dsa_pub: Uint8Array;
65
+ /**
66
+ * Optional. If supplied, the verifier asserts the envelope's `payloadType`
67
+ * equals this value before verifying signatures — an explicit type-pinning
68
+ * check on top of the structural PAE binding. A mismatch fails with
69
+ * `payload-type-mismatch`.
70
+ */
71
+ expectedPayloadType?: string;
72
+ }
73
+ export interface VerifyAttestationResult {
74
+ /** True only when BOTH required signatures verified over the same PAE. */
75
+ valid: boolean;
76
+ /**
77
+ * Human-readable failure reasons. Empty when valid. Possible values:
78
+ * 'envelope-malformed', 'payload-type-mismatch', 'missing-ed25519',
79
+ * 'missing-ml-dsa-65', 'ed25519-malformed', 'ml-dsa-malformed',
80
+ * 'ed25519-invalid', 'ml-dsa-invalid'.
81
+ */
82
+ reasons: string[];
83
+ }
84
+ /**
85
+ * Verify a hybrid DSSE attestation envelope. Returns `valid: true` only when
86
+ * the envelope carries BOTH an `ed25519` and an `ml-dsa-65` signature and
87
+ * BOTH verify against the supplied public keys over `PAE(payloadType,
88
+ * payload)`. The payloadType is bound into the signed bytes, so a signature
89
+ * minted for a different payloadType will not verify.
90
+ */
91
+ export declare function verifyAttestation(input: VerifyAttestationInput): VerifyAttestationResult;
92
+ //# sourceMappingURL=attestation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attestation.d.ts","sourceRoot":"","sources":["../src/attestation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAwB,MAAM,YAAY,CAAA;AAE3E,uEAAuE;AACvE,eAAO,MAAM,WAAW,YAAY,CAAA;AACpC,eAAO,MAAM,aAAa,cAAc,CAAA;AAExC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAYjF;AAED,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,sCAAsC;IACtC,WAAW,EAAE,UAAU,CAAA;IACvB,sCAAsC;IACtC,UAAU,EAAE,UAAU,CAAA;IACtB;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,uBAAuB;IACtC,0EAA0E;IAC1E,KAAK,EAAE,OAAO,CAAA;IACd;;;;;OAKG;IACH,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,uBAAuB,CAsExF"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * @synoi/sraid — attestation.ts
3
+ *
4
+ * L2 attestation layer: a DSSE (Dead Simple Signing Envelope) profile that
5
+ * carries one or more detached signatures over a SRAID object's canonical
6
+ * payload, with the payload TYPE structurally bound into the signed bytes.
7
+ *
8
+ * Why this exists (SRAID F7 / Adversary A4, SRAID_FOUNDATION_PUNCHLIST A3,
9
+ * OBJECT_MODEL_CLEANSHEET §3.2): the legacy `SignatureEnvelope` signs the
10
+ * bare canonical bytes with NO payload-type binding. Because every SRAID
11
+ * object shape (decision receipt, capability grant, memory record, identity
12
+ * disclosure, supply-chain attestation, …) is signed identically over its
13
+ * canonical bytes, a signature minted for one type could be replayed as a
14
+ * valid signature for a different type whose canonical bytes happen to match
15
+ * — a cross-type / confused-deputy hazard. DSSE closes this by signing the
16
+ * Pre-Authentication Encoding (PAE), which prepends the payloadType and the
17
+ * lengths of both fields, so the type is part of what is signed.
18
+ *
19
+ * SynOI policy (the AND rule): a SRAID attestation MUST carry BOTH an
20
+ * `ed25519` and an `ml-dsa-65` signature over the SAME PAE, and the verifier
21
+ * here requires BOTH to verify before returning `valid: true`. DSSE itself
22
+ * is an OR-of-signatures envelope; the both-required rule lives in this
23
+ * verifier and in the SRAID spec, not in DSSE. This preserves the hybrid
24
+ * classical + post-quantum property of the legacy scheme.
25
+ *
26
+ * Profile: JSON (`payloadType` is a media type string; `payload` is the
27
+ * canonical UTF-8 string). A future CBOR profile would use COSE (RFC 9052);
28
+ * it is reserved, not implemented here.
29
+ *
30
+ * Identity stability: signatures live in a detached `signatures[]` array and
31
+ * are NEVER part of the OID hash input (see `cdroContentCore` in oid.ts), so
32
+ * adding, rotating, or replacing a signature never changes the object's OID.
33
+ */
34
+ import { verifyEd25519 } from './ed25519.js';
35
+ import { decodeBase64Strict } from './internal/base64.js';
36
+ import { verifyMlDsa65 } from './mldsa.js';
37
+ /** The single supported algorithm identifiers for the JSON profile. */
38
+ export const ALG_ED25519 = 'ed25519';
39
+ export const ALG_ML_DSA_65 = 'ml-dsa-65';
40
+ /**
41
+ * The DSSE Pre-Authentication Encoding (PAE).
42
+ *
43
+ * Per the DSSE spec:
44
+ *
45
+ * PAE(type, body) = "DSSEv1" SP LEN(type) SP type SP LEN(body) SP body
46
+ *
47
+ * where:
48
+ * - SP is a single ASCII space (0x20),
49
+ * - LEN(x) is the ASCII-decimal byte length of x's UTF-8 encoding,
50
+ * - type and body are the raw UTF-8 bytes (NOT base64).
51
+ *
52
+ * Binding the payloadType (and both lengths) into the signed bytes is what
53
+ * makes a signature non-transferable across object types. Returns the raw
54
+ * bytes to be signed/verified.
55
+ */
56
+ export function pae(payloadType, payload) {
57
+ const enc = new TextEncoder();
58
+ const typeBytes = enc.encode(payloadType);
59
+ const bodyBytes = typeof payload === 'string' ? enc.encode(payload) : payload;
60
+ const prefix = enc.encode(`DSSEv1 ${typeBytes.length} ${payloadType} ${bodyBytes.length} `);
61
+ const out = new Uint8Array(prefix.length + bodyBytes.length);
62
+ out.set(prefix, 0);
63
+ out.set(bodyBytes, prefix.length);
64
+ return out;
65
+ }
66
+ /**
67
+ * Verify a hybrid DSSE attestation envelope. Returns `valid: true` only when
68
+ * the envelope carries BOTH an `ed25519` and an `ml-dsa-65` signature and
69
+ * BOTH verify against the supplied public keys over `PAE(payloadType,
70
+ * payload)`. The payloadType is bound into the signed bytes, so a signature
71
+ * minted for a different payloadType will not verify.
72
+ */
73
+ export function verifyAttestation(input) {
74
+ const reasons = [];
75
+ const env = input.envelope;
76
+ if (env === null ||
77
+ typeof env !== 'object' ||
78
+ typeof env.payloadType !== 'string' ||
79
+ env.payloadType.length === 0 ||
80
+ typeof env.payload !== 'string' ||
81
+ !Array.isArray(env.signatures)) {
82
+ return { valid: false, reasons: ['envelope-malformed'] };
83
+ }
84
+ if (input.expectedPayloadType !== undefined &&
85
+ env.payloadType !== input.expectedPayloadType) {
86
+ return { valid: false, reasons: ['payload-type-mismatch'] };
87
+ }
88
+ // The signed bytes: PAE binds payloadType + payload together.
89
+ const message = pae(env.payloadType, env.payload);
90
+ // Find the required hybrid pair. The AND policy: both must be present.
91
+ const edEntry = findSig(env.signatures, ALG_ED25519);
92
+ const mlEntry = findSig(env.signatures, ALG_ML_DSA_65);
93
+ if (!edEntry)
94
+ reasons.push('missing-ed25519');
95
+ if (!mlEntry)
96
+ reasons.push('missing-ml-dsa-65');
97
+ let edOk = false;
98
+ let mlOk = false;
99
+ if (edEntry) {
100
+ let edSig = null;
101
+ try {
102
+ edSig = fromBase64(edEntry.sig);
103
+ }
104
+ catch {
105
+ reasons.push('ed25519-malformed');
106
+ }
107
+ if (edSig) {
108
+ try {
109
+ edOk = verifyEd25519(edSig, message, input.ed25519_pub);
110
+ }
111
+ catch {
112
+ edOk = false;
113
+ }
114
+ if (!edOk)
115
+ reasons.push('ed25519-invalid');
116
+ }
117
+ }
118
+ if (mlEntry) {
119
+ let mlSig = null;
120
+ try {
121
+ mlSig = fromBase64(mlEntry.sig);
122
+ }
123
+ catch {
124
+ reasons.push('ml-dsa-malformed');
125
+ }
126
+ if (mlSig) {
127
+ try {
128
+ mlOk = verifyMlDsa65(mlSig, message, input.ml_dsa_pub);
129
+ }
130
+ catch {
131
+ mlOk = false;
132
+ }
133
+ if (!mlOk)
134
+ reasons.push('ml-dsa-invalid');
135
+ }
136
+ }
137
+ return { valid: edOk && mlOk && !!edEntry && !!mlEntry, reasons };
138
+ }
139
+ // ── Helpers ───────────────────────────────────────────────────────────────────
140
+ function findSig(sigs, alg) {
141
+ for (const s of sigs) {
142
+ if (s && typeof s === 'object' && s.alg === alg && typeof s.sig === 'string') {
143
+ return s;
144
+ }
145
+ }
146
+ return undefined;
147
+ }
148
+ // Strict standard base64. Throws Error('base64-malformed') on any deviation
149
+ // (illegal char, bad length, bad padding) rather than silently truncating.
150
+ // Both call sites wrap this in try/catch and map the throw to a *-malformed
151
+ // reason, so verifyAttestation never throws.
152
+ function fromBase64(s) {
153
+ return decodeBase64Strict(s);
154
+ }
155
+ //# sourceMappingURL=attestation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attestation.js","sourceRoot":"","sources":["../src/attestation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,351 @@
1
+ /**
2
+ * @synoi/sraid — authority.ts
3
+ *
4
+ * L4 authority VERIFIER for CDRO objects (the authorized axis).
5
+ *
6
+ * This is deliberately more than a shape check. Per the Adversary review
7
+ * (panel A6: "ship a verifier, not just a schema"), an attacker who can
8
+ * attach any well-shaped `authority` block to an object would otherwise
9
+ * forge authorization for free. So this module verifies, locally and
10
+ * offline, the parts of authorization that ARE locally checkable:
11
+ *
12
+ * 1. STRUCTURE — the object carries a present, well-formed authority
13
+ * block (grant reference present; decision verb, if any, is a valid
14
+ * GAP verb; intent ref well-formed).
15
+ * 2. BINDING — the object's authority block actually references the
16
+ * supplied grant (the grant's OID matches `authority.grant_oid`),
17
+ * AND the grant is itself a hash-honest CDRO whose recomputed OID
18
+ * equals its claimed OID (so the grant body cannot be swapped under
19
+ * a fixed OID reference).
20
+ * 3. SIGNATURE — the grant carries a valid hybrid (Ed25519 + ML-DSA-65)
21
+ * signature over its own content core, when grant signing material
22
+ * and verifier public keys are supplied. A grant with no/invalid
23
+ * signature does not authorize.
24
+ * 4. COVERAGE — the grant's capability scopes cover the requested
25
+ * object type / action (dotted-taxonomy match with segment-boundary
26
+ * wildcards), and the grant has not expired relative to the object's
27
+ * creation time. Both are computable from the bytes in hand.
28
+ *
29
+ * What this module does NOT and CANNOT do offline — stated honestly,
30
+ * never silently assumed (CLAIMS_DISCIPLINE):
31
+ *
32
+ * - LIVE REVOCATION — whether the grant has since been revoked.
33
+ * - EXISTENCE — whether the grant OID actually resolves to a
34
+ * published, retrievable grant at all (when the
35
+ * caller did not supply the grant material).
36
+ *
37
+ * Both require the OID Resolver, which is presently undeployed
38
+ * (SRAID_FOUNDATION_PUNCHLIST C). This module DEFINES the resolver
39
+ * interface (`AuthorityResolver`) and, when a resolver is supplied, calls
40
+ * it and folds its answer into the result — but when no resolver is
41
+ * supplied, the result is explicitly marked `revocation_checked: false`
42
+ * and `existence_checked: false` so a caller can never mistake a
43
+ * locally-passing verification for a live one.
44
+ *
45
+ * DELEGATION CHAINS (`verifyDelegationChain`, K2) — VERIFY-ONLY. This module
46
+ * also carries a synchronous, offline delegation-chain verifier. It is
47
+ * deliberately scoped to verification with NO enforcement wiring and NO
48
+ * resolver: the caller supplies the ordered ancestors and the per-link
49
+ * verifier keys, and the function makes NO live claim. It ALWAYS returns
50
+ * `revocation_checked: false`, `not_revoked: false`, and
51
+ * `existence_checked: false` — those fields are LITERAL-TYPED `false` so the
52
+ * type system itself forbids a future edit from quietly asserting a live,
53
+ * resolver-backed claim from an offline function (CLAIMS_DISCIPLINE made
54
+ * structural). Synchronicity is intentional: with no Promise overload there is
55
+ * no place for a resolver call, which is what makes the no-live-claim
56
+ * guarantee structural rather than merely documented.
57
+ */
58
+ import type { CDRO } from './types.js';
59
+ /**
60
+ * Match a capability `target` against a grant `pattern`. Pure string logic,
61
+ * re-stated here so L0 stays dependency-free (the same rule lives in
62
+ * `@synoi/gap-types` `capabilityMatches`; L0 must not depend on L3).
63
+ *
64
+ * - exact match → true
65
+ * - '*' → match-all
66
+ * - 'skill.*' matches 'skill.create' and deeper (segment-boundary only).
67
+ * A non-boundary 'admin.us*' must NOT match 'admin.users.delete'
68
+ * (privilege-escalation footgun) — only a '.'-anchored '*' is a wildcard.
69
+ */
70
+ export declare function capabilityCovers(pattern: string, target: string): boolean;
71
+ /**
72
+ * The live-state interface that the OID Resolver implements. It is the ONLY
73
+ * source of truth for the two properties that cannot be checked offline:
74
+ * whether a grant currently exists (resolves) and whether it has been
75
+ * revoked. RESOLVER-DEPENDENT: undeployed today
76
+ * (SRAID_FOUNDATION_PUNCHLIST C). Defined here so callers and a future
77
+ * resolver agree on the contract; verifyAuthority works without it but
78
+ * marks the corresponding result fields as not-checked.
79
+ */
80
+ export interface AuthorityResolver {
81
+ /**
82
+ * Resolve a grant OID to its current status. Implementations should
83
+ * return `{ exists: false }` for an unknown OID and `{ exists: true,
84
+ * revoked: true, revoked_at_ms }` for a revoked one.
85
+ */
86
+ resolveGrantStatus(grantOid: string): Promise<GrantStatus> | GrantStatus;
87
+ }
88
+ export interface GrantStatus {
89
+ /** Whether the grant OID resolves to a known, published grant. */
90
+ exists: boolean;
91
+ /** Whether the grant has been revoked. Only meaningful when `exists`. */
92
+ revoked?: boolean;
93
+ /** When the revocation took effect, if revoked. */
94
+ revoked_at_ms?: number;
95
+ }
96
+ export interface VerifyAuthorityInput {
97
+ /**
98
+ * The object whose authority block is being verified. Its `authority`
99
+ * field is read; the object's `type` is used as the action target for the
100
+ * coverage check unless `action` overrides it.
101
+ */
102
+ object: CDRO;
103
+ /**
104
+ * The capability / action the object claims to perform, for the coverage
105
+ * check. Defaults to `object.type`. For an Althing receipt this is
106
+ * typically the invoked capability (e.g. `email.bulk_delete`).
107
+ */
108
+ action?: string;
109
+ /**
110
+ * The authorizing grant CDRO, when available. Supplying it enables the
111
+ * BINDING, SIGNATURE, and COVERAGE checks. Omit it to do STRUCTURE-only
112
+ * verification (then `grant_supplied: false`).
113
+ */
114
+ grant?: CDRO<GrantBodyShape>;
115
+ /** Verifier public keys for the grant's hybrid signature. */
116
+ grant_ed25519_pub?: Uint8Array;
117
+ grant_ml_dsa_pub?: Uint8Array;
118
+ /**
119
+ * Expected DSSE payloadType for the grant's attestation envelope. Defaults
120
+ * to `'application/vnd.synoi.sraid+json'`. Override when the grant was
121
+ * issued with a custom media type.
122
+ */
123
+ grant_payload_type?: string;
124
+ /**
125
+ * Optional live-state resolver. When supplied, revocation + existence are
126
+ * checked and folded into the result; when omitted those remain
127
+ * explicitly unchecked (resolver-dependent).
128
+ */
129
+ resolver?: AuthorityResolver;
130
+ }
131
+ /**
132
+ * The minimum grant body shape this verifier reads for coverage + expiry.
133
+ * A superset of `@synoi/gap-types` `CapabilityGrantBody`; kept structural so
134
+ * L0 does not depend on L3.
135
+ */
136
+ export interface GrantBodyShape {
137
+ capability_scopes?: Array<{
138
+ capability?: unknown;
139
+ }>;
140
+ expires_at_ms?: number | null;
141
+ /**
142
+ * Issuer of this grant. Mirrors the gateway `CapabilityGrantBody.granted_by`
143
+ * (synoi-gateway/src/gap/types.ts). VERIFY-ONLY: read by
144
+ * `verifyDelegationChain` to check that a child's issuer equals its parent's
145
+ * grantee. Kept OPTIONAL/structural so L0 stays L3-independent.
146
+ */
147
+ granted_by?: string;
148
+ /**
149
+ * Subject this grant is issued to. Mirrors the gateway
150
+ * `CapabilityGrantBody.grantee.actor_oid`. VERIFY-ONLY: a child grant chains
151
+ * under this grant iff `child.granted_by === this.grantee.actor_oid`.
152
+ */
153
+ grantee?: {
154
+ actor_oid?: string;
155
+ };
156
+ /**
157
+ * OID of the parent grant in a delegation chain. Absent/null = a root grant.
158
+ * VERIFY-ONLY linkage field; it is NOT consulted for any enforcement here.
159
+ * The chain order and ancestry are caller-supplied to `verifyDelegationChain`
160
+ * (the verifier never fetches), so this is informational/auditable, not a
161
+ * resolution hook.
162
+ */
163
+ parent_grant_oid?: string | null;
164
+ }
165
+ export interface VerifyAuthorityResult {
166
+ /**
167
+ * True only when every LOCALLY CHECKABLE step that was attempted passed.
168
+ * NOTE: this is `false` for `valid` does NOT imply the grant is revoked;
169
+ * read the per-check fields. Crucially, `authorized === true` from this
170
+ * function means "locally authorized" — it is NOT a claim about live
171
+ * revocation unless `revocation_checked` is also true.
172
+ */
173
+ authorized: boolean;
174
+ /** Structure check: authority block present + well-formed. */
175
+ structure_ok: boolean;
176
+ /** Whether a grant was supplied (enables binding/signature/coverage). */
177
+ grant_supplied: boolean;
178
+ /** Binding check: object.authority.grant_oid === grant's recomputed OID. */
179
+ binding_ok: boolean;
180
+ /** Signature check: grant carries a valid hybrid signature (when keys given). */
181
+ signature_ok: boolean;
182
+ /** Whether signature was actually checked (keys + grant present). */
183
+ signature_checked: boolean;
184
+ /** Coverage check: grant scope covers the action AND grant not expired. */
185
+ coverage_ok: boolean;
186
+ /** RESOLVER-DEPENDENT — true only if a resolver confirmed the grant exists. */
187
+ existence_checked: boolean;
188
+ existence_ok: boolean;
189
+ /** RESOLVER-DEPENDENT — true only if a resolver confirmed not-revoked. */
190
+ revocation_checked: boolean;
191
+ not_revoked: boolean;
192
+ /** Human-readable failure reasons. Empty when fully authorized. */
193
+ reasons: string[];
194
+ }
195
+ /**
196
+ * Verify the authority of a CDRO object. Synchronous local checks plus an
197
+ * optional resolver call. When a resolver is supplied this returns a
198
+ * Promise; otherwise it returns the result directly.
199
+ */
200
+ export declare function verifyAuthority(input: VerifyAuthorityInput & {
201
+ resolver?: undefined;
202
+ }): VerifyAuthorityResult;
203
+ export declare function verifyAuthority(input: VerifyAuthorityInput & {
204
+ resolver: AuthorityResolver;
205
+ }): Promise<VerifyAuthorityResult>;
206
+ /**
207
+ * Hard cap on delegation depth. Checked BEFORE any hashing or signature work,
208
+ * so an over-long chain is a cheap rejection (DoS guard) and never triggers
209
+ * crypto. A chain of `links.length > MAX_DELEGATION_DEPTH` fails closed.
210
+ */
211
+ export declare const MAX_DELEGATION_DEPTH = 8;
212
+ /** The hybrid verifier public keys for one link's issuer. */
213
+ export interface LinkPubkeys {
214
+ /** Raw 32-byte Ed25519 public key. */
215
+ ed25519: Uint8Array;
216
+ /** Raw ML-DSA-65 public key bytes. */
217
+ ml_dsa: Uint8Array;
218
+ }
219
+ /**
220
+ * Per-hop result. Index `i` describes child `links[i]` verified UNDER parent
221
+ * `links[i+1]`. The terminal link (root) has no parent hop, so `per_hop` has
222
+ * `depth - 1` entries.
223
+ */
224
+ export interface HopResult {
225
+ /** Index of the child link in the leaf->root `links` array. */
226
+ child_index: number;
227
+ /** child.body.granted_by === parent.body.grantee.actor_oid. */
228
+ granted_by_ok: boolean;
229
+ /** Every child scope is covered by some parent scope (no widening). */
230
+ attenuation_ok: boolean;
231
+ /** Child expiry does not widen the parent's (monotone narrowing). */
232
+ expiry_ok: boolean;
233
+ }
234
+ export interface VerifyDelegationChainInput {
235
+ /** The leaf grant (most-attenuated, end of the chain). */
236
+ leaf: CDRO<GrantBodyShape>;
237
+ /**
238
+ * Ancestors, ordered leaf-adjacent -> root: the leaf's parent first, the
239
+ * root grant last. The full chain is `links = [leaf, ...ancestors]`, so
240
+ * `links[i]` is the child of `links[i+1]` and `links[links.length-1]` is the
241
+ * terminal root grant.
242
+ */
243
+ ancestors: CDRO<GrantBodyShape>[];
244
+ /**
245
+ * Hybrid verifier keys, index-aligned to `links` (so `linkPubkeys[i]` is the
246
+ * issuer key of `links[i]`). Caller-supplied: the verifier never fetches
247
+ * keys. `linkPubkeys[links.length-1]` MUST equal `rootPubkeys`.
248
+ */
249
+ linkPubkeys: LinkPubkeys[];
250
+ /**
251
+ * The trusted root principal's keys. The terminal link's signer key MUST
252
+ * deep-equal these, else the chain does not anchor to a known root.
253
+ */
254
+ rootPubkeys: LinkPubkeys;
255
+ /**
256
+ * Pin the DSSE payloadType for every link. Defaults to the SRAID grant
257
+ * media type.
258
+ */
259
+ attestationPayloadType?: string;
260
+ /**
261
+ * Optional requested action. When supplied, the leaf grant's capability
262
+ * scopes MUST cover this action (GATE 5). If uncovered, `authorized` is
263
+ * false and `action_ok` is false. When omitted, GATE 5 is skipped and
264
+ * `action_checked` is false (vacuous pass — existing callers unaffected).
265
+ */
266
+ action?: string;
267
+ }
268
+ /**
269
+ * Result of `verifyDelegationChain`. Mirrors `VerifyAuthorityResult`'s
270
+ * honesty discipline: the three live-claim fields are LITERAL-TYPED `false`
271
+ * so the type system itself forbids a future edit from quietly asserting a
272
+ * resolver-backed claim from this offline, verify-only function.
273
+ */
274
+ export interface VerifyDelegationChainResult {
275
+ /** True iff every hop check, every link signature, and the root anchor passed. */
276
+ authorized: boolean;
277
+ /** Number of grants in the chain (`links.length`). */
278
+ depth: number;
279
+ /** depth >= 1 && depth <= MAX_DELEGATION_DEPTH. Checked before any crypto. */
280
+ depth_ok: boolean;
281
+ /** Every child.granted_by === parent.grantee.actor_oid. */
282
+ links_ok: boolean;
283
+ /** Every child scope covered by some parent scope, all hops (no widening). */
284
+ attenuation_ok: boolean;
285
+ /** Monotone expiry narrowing, all hops. */
286
+ expiry_ok: boolean;
287
+ /** Every link carried a valid hybrid DSSE attestation over its content core. */
288
+ signatures_ok: boolean;
289
+ /** False if any link lacked an attestation, or if no crypto ran (over-depth). */
290
+ signatures_checked: boolean;
291
+ /** Every link OID is hash-honest (recomputed === claimed). */
292
+ oids_ok: boolean;
293
+ /** Terminal link signer key == rootPubkeys. */
294
+ root_ok: boolean;
295
+ /**
296
+ * True iff the requested action is covered by some leaf scope.
297
+ * When `action` was not supplied, this is true (vacuous pass).
298
+ */
299
+ action_ok: boolean;
300
+ /**
301
+ * True when an `action` was supplied and GATE 5 ran; false when the caller
302
+ * omitted `action` (GATE 5 skipped).
303
+ */
304
+ action_checked: boolean;
305
+ /** ALWAYS false — verify-only, no live revocation claim (literal type). */
306
+ revocation_checked: false;
307
+ /** ALWAYS false — verify-only (literal type). */
308
+ not_revoked: false;
309
+ /** ALWAYS false — no resolver, no existence claim (literal type). */
310
+ existence_checked: false;
311
+ /** Per-hop breakdown; index i = child links[i] under parent links[i+1]. */
312
+ per_hop: HopResult[];
313
+ /** Human-readable failure reasons. Empty when fully authorized. */
314
+ reasons: string[];
315
+ }
316
+ /**
317
+ * Verify a delegation chain OFFLINE (K2). VERIFY-ONLY: there is no enforcement
318
+ * wiring and no resolver — the caller supplies the ordered ancestors and the
319
+ * per-link verifier keys, and this function makes NO live claim. It ALWAYS
320
+ * returns `revocation_checked: false` and `existence_checked: false`; those
321
+ * remain RESOLVER-DEPENDENT (SRAID_FOUNDATION_PUNCHLIST C) and are explicitly
322
+ * out of scope here. The function is synchronous (no Promise overload), which
323
+ * is what makes "no live claim" structural rather than merely documented.
324
+ *
325
+ * The gate runs in this fixed order; DEPTH is checked BEFORE any crypto:
326
+ *
327
+ * GATE 0 DEPTH CAP — depth in [1, MAX_DELEGATION_DEPTH]; else return with
328
+ * NO hashing or signature work (cheap DoS guard).
329
+ * GATE 1 OID HONESTY — every link's recomputed content-core OID equals its
330
+ * claimed `oid` (rejects a body swapped under a fixed
331
+ * OID reference).
332
+ * GATE 2 PER-HOP — for each child links[i] under parent links[i+1]:
333
+ * (a) granted_by linkage, (b) scope attenuation (every
334
+ * child scope covered by some parent scope; empty
335
+ * child scopes = FAIL — a grant of nothing is not
336
+ * vacuously attenuated), (c) expiry monotone narrowing
337
+ * (null parent = unbounded; null child under a bounded
338
+ * parent = widening = FAIL).
339
+ * GATE 3 SIGNATURES — every link carries a hybrid DSSE attestation
340
+ * (ed25519 AND ml-dsa-65) over PAE(payloadType,
341
+ * payload), and the attestation payload equals
342
+ * canonicalize(cdroContentCore(link)) (payload-swap
343
+ * guard). A missing attestation sets signatures_checked
344
+ * false for that link and fails.
345
+ * GATE 4 ROOT ANCHOR — the terminal link's issuer key deep-equals
346
+ * rootPubkeys.
347
+ *
348
+ * `authorized` is the AND of every gate.
349
+ */
350
+ export declare function verifyDelegationChain(input: VerifyDelegationChainInput): VerifyDelegationChainResult;
351
+ //# sourceMappingURL=authority.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authority.d.ts","sourceRoot":"","sources":["../src/authority.ts"],"names":[],"mappings":"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"}