@sanning/proof 0.6.0 → 0.8.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.
@@ -12,6 +12,32 @@ export declare const ANCHOR_TRACE_BODY_TYPE_V1 = "sanning.anchor.trace/v1";
12
12
  /** Every anchor-trace body this kernel verifies. Order is newest-first. */
13
13
  export declare const ANCHOR_TRACE_BODY_TYPES: readonly ["sanning.anchor.trace/v2", "sanning.anchor.trace/v1"];
14
14
  export declare const EXPORT_BODY_TYPE = "sanning.evidence.export/v1";
15
+ /**
16
+ * The Sanning-signed interval stamp body (evidence-bundle.md §5.2, DL-58).
17
+ *
18
+ * Its own `body_type` rather than a widened anchor-trace body, and the reason
19
+ * is the whole decision: an anchor-trace checkpoint carries a PRODUCER-signed
20
+ * `sanning.events/v1` envelope, and a stamp has no producer signature at all —
21
+ * Sanning places it, under DL-52, for a customer who holds no chain identity.
22
+ * The two rejected options were making `envelope` optional and synthesising an
23
+ * envelope that Sanning signs; the second would have made a Sanning
24
+ * attestation indistinguishable ON THE WIRE from a producer's, which is
25
+ * unrecoverable once witnessed.
26
+ */
27
+ export declare const STAMP_TRACE_BODY_TYPE = "sanning.stamp.trace/v1";
28
+ export declare const STAMP_EVIDENCE_BODY_TYPE = "sanning.stamp.evidence/v1";
29
+ /**
30
+ * The version string INSIDE a witnessed stamp body — a different string from
31
+ * the `body_type` above, and the two are easy to confuse.
32
+ *
33
+ * `sanning.stamp.trace/v1` discriminates the BUNDLE BODY: it is the reader's
34
+ * dispatch key. `sanning.stamp/v1` is the control plane's own version of the
35
+ * bytes it hands a witness (`control-plane/src/stamp-tree.ts`,
36
+ * `STAMP_BODY_VERSION`). A `sanning.stamp.trace/v1` body pins the inner
37
+ * version to exactly this value: two answers to one question inside one
38
+ * signature is the §5.1.2 mixed-vocabulary reject, one layer down.
39
+ */
40
+ export declare const STAMP_BODY_VERSION = "sanning.stamp/v1";
15
41
  export interface EvidenceIssuer {
16
42
  kind: string;
17
43
  tenant_id?: string;
@@ -85,6 +111,78 @@ export interface AnchorTraceBody {
85
111
  checkpoints: TraceCheckpoint[];
86
112
  events: TraceEvent[];
87
113
  }
114
+ /**
115
+ * One sub-tree of a stamp, as the WITNESSED bytes carry it.
116
+ *
117
+ * Keyed in the body by a blinded reference (an HMAC under a per-org secret we
118
+ * never publish), so a reader learns that the org runs N agents and their
119
+ * relative volumes and learns no name. The RANGE is deliberately in the clear:
120
+ * it is what makes a later per-agent slice claim checkable by a third party
121
+ * without Sanning, and hiding it would put us back in the trust path.
122
+ */
123
+ export interface StampSubtree {
124
+ first_leaf: number;
125
+ leaf_count: number;
126
+ /** Hex RFC-9162 root over this sub-tree's leaves alone. */
127
+ root: string;
128
+ }
129
+ /**
130
+ * The stamp body as the control plane witnesses it
131
+ * (`control-plane/src/stamp-tree.ts`, `StampBody`).
132
+ *
133
+ * Never read from the bundle directly — it is parsed out of `stamp_bytes`,
134
+ * which is the only authority. Present as a type so the parse has a shape.
135
+ */
136
+ export interface StampBody {
137
+ stamp_version: string;
138
+ /** The org, BLINDED. Not an org id, and not reversible without the secret. */
139
+ org_ref: string;
140
+ interval_start: string;
141
+ interval_end: string;
142
+ merkle_root: string;
143
+ leaf_count: number;
144
+ subtrees: Record<string, StampSubtree>;
145
+ }
146
+ /** One entry of a `sanning.stamp.trace/v1` body's `stamps[]` (§5.2). */
147
+ export interface StampEntry {
148
+ /**
149
+ * The stamp's identity within this bundle, DERIVED: hex SHA-256 of the
150
+ * DECODED `stamp_bytes`, not of the hex text. A verifier MUST recompute it.
151
+ */
152
+ stamp_ref: string;
153
+ /** Lowercase hex of the exact JCS bytes that were handed to the witness. */
154
+ stamp_bytes: string;
155
+ /**
156
+ * Where the stamp was witnessed, IF IT HAS BEEN (§5.1.1). Absent is honest:
157
+ * a sealed-but-unconfirmed stamp is witnessed by nobody, and an emitter that
158
+ * filled this in from a submission receipt would be claiming a chain
159
+ * position that does not exist yet.
160
+ */
161
+ anchor_ref?: AnchorRef;
162
+ }
163
+ export interface StampTraceBody {
164
+ stamps: StampEntry[];
165
+ }
166
+ /** §5.3's inclusion: §5.1's shape with `stamp_ref` as the join key. */
167
+ export interface StampEvidenceInclusion {
168
+ leaf_hash: string;
169
+ leaf_index: number;
170
+ leaf_count: number;
171
+ audit_path: string[];
172
+ /** Resolves against `stamps[].stamp_ref` in the SAME body. */
173
+ stamp_ref: string;
174
+ }
175
+ export interface StampEvidenceEvent {
176
+ envelope: Envelope;
177
+ record_bytes?: string;
178
+ content?: string;
179
+ inclusion: StampEvidenceInclusion;
180
+ }
181
+ export interface StampEvidenceBody {
182
+ /** Byte-identical to §5.2.2 — one definition, one place to change. */
183
+ stamps: StampEntry[];
184
+ events: StampEvidenceEvent[];
185
+ }
88
186
  export interface EvidenceBundle {
89
187
  spec_version: string;
90
188
  body_type: string;
@@ -149,6 +247,54 @@ export interface EventResult {
149
247
  ok: boolean;
150
248
  errors: string[];
151
249
  }
250
+ /** One sub-tree's recomputed result (§5.2). */
251
+ export interface StampSubtreeResult {
252
+ /** The blinded key the body spells it under. Meaningless without the org's secret. */
253
+ ref: string;
254
+ firstLeaf: number;
255
+ leafCount: number;
256
+ root: string;
257
+ }
258
+ /** One `stamps[]` entry's result (§5.2). */
259
+ export interface StampResult {
260
+ /** The stamp's derived identity, as the bundle spells it. "" when unusable. */
261
+ stampRef: string;
262
+ /** The asserted `stamp_ref` equals SHA-256 of the decoded `stamp_bytes`. */
263
+ stampRefOk: boolean;
264
+ /**
265
+ * The witnessed bytes decoded, parsed, and re-canonicalized to themselves.
266
+ *
267
+ * The last clause is not pedantry. The plane stores these bytes as TEXT and
268
+ * replays them verbatim precisely because a round-trip through a normalizing
269
+ * serializer is not guaranteed to reproduce what was signed; a body that is
270
+ * not JCS-canonical is one that every re-deriving reader hashes differently.
271
+ */
272
+ bodyOk: boolean;
273
+ stampVersion: string | null;
274
+ intervalStart: string | null;
275
+ intervalEnd: string | null;
276
+ merkleRoot: string | null;
277
+ leafCount: number | null;
278
+ /**
279
+ * Every sub-tree range accounts for exactly one leaf of the stamp: the
280
+ * ranges sorted by `first_leaf` tile `[0, leaf_count)` with no gap and no
281
+ * overlap, and their counts sum to `leaf_count`.
282
+ */
283
+ subtreesOk: boolean;
284
+ subtrees: StampSubtreeResult[];
285
+ /**
286
+ * Where it was witnessed, or `null` for a stamp nothing has witnessed yet.
287
+ *
288
+ * `null` is NOT a failure and never an accusation — it is the honest state
289
+ * of every stamp for the first minutes of its life and the permanent state
290
+ * of every stamp when no witness is configured. It does hold the bundle at
291
+ * `partial`: a stamp is Sanning's own assertion until something independent
292
+ * carries it.
293
+ */
294
+ anchorRef: AnchorRef | null;
295
+ ok: boolean;
296
+ errors: string[];
297
+ }
152
298
  export interface EvidenceBundleResult {
153
299
  status: EvidenceStatus;
154
300
  specVersionOk: boolean;
@@ -160,6 +306,7 @@ export interface EvidenceBundleResult {
160
306
  events: EventResult[];
161
307
  assertedStatus: string | null;
162
308
  export?: ExportResult;
309
+ stamps?: StampResult[];
163
310
  errors: string[];
164
311
  }
165
312
  export interface AttestationRecord {
@@ -304,6 +451,7 @@ export interface DisclosedContentResult {
304
451
  * know their payload is text decode it themselves and own that assumption.
305
452
  */
306
453
  export declare function disclosedContent(bundle: unknown, options?: VerifyEvidenceOptions): Promise<DisclosedContentResult>;
454
+ export declare function resolveTraceEvents(bundle: unknown): TraceEvent[] | undefined;
307
455
  export interface ComposeVerdictResult {
308
456
  verdict: VerdictObject;
309
457
  sourceStatus: EvidenceStatus;