@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.
- package/README.md +1 -1
- package/dist/chain.d.ts +99 -0
- package/dist/chain.js +389 -0
- package/dist/cli.js +42 -2
- package/dist/evidence.d.ts +148 -0
- package/dist/evidence.js +603 -70
- package/dist/index.d.ts +4 -2
- package/dist/index.js +22 -1
- package/dist/verifier.js +46 -7
- package/package.json +1 -1
- package/src/chain.ts +500 -0
- package/src/cli.ts +50 -1
- package/src/evidence.ts +813 -74
- package/src/index.ts +46 -0
- package/src/verifier.ts +49 -7
- package/vectors/chain-reading.json +293 -0
package/dist/evidence.d.ts
CHANGED
|
@@ -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;
|