@mikeargento/bitgraph-verify 1.0.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.
@@ -0,0 +1,705 @@
1
+ /**
2
+ * bitgraph-core types
3
+ *
4
+ * All public-facing data structures for the BitGraph proof system.
5
+ * This file intentionally contains no logic.
6
+ */
7
+ /**
8
+ * Declares the enforcement tier of the host adapter that produced a proof.
9
+ *
10
+ * This field is SIGNED and therefore tamper-evident in transit.
11
+ * However, it is self-reported by the adapter and MUST NOT be treated as
12
+ * self-authenticating by verifiers.
13
+ *
14
+ * Trust is established by verifier policy (allowedMeasurements +
15
+ * attestation chain validation), not by this field alone.
16
+ *
17
+ * Tier semantics:
18
+ *
19
+ * "stub"
20
+ * Software-only. Key lives in process memory. No hardware protection.
21
+ * Suitable for development, testing, and local demos only.
22
+ * measurement MAY be a synthetic sentinel value.
23
+ *
24
+ * "hw-key"
25
+ * Hardware-protected signing key (Secure Enclave / TPM class).
26
+ * The key is non-exportable from the hardware boundary.
27
+ * However, the commit gate runs outside the measured boundary —
28
+ * the host feeds digests to the hardware for signing.
29
+ * This provides hardware-bound identity but NOT causal enforcement.
30
+ * measurement SHOULD identify the key environment.
31
+ *
32
+ * "measured-tee"
33
+ * Full causal enforcement. The commit gate, key management, nonce
34
+ * generation, monotonic counter, and signing all execute inside the
35
+ * attested enclave boundary. The host is treated as untrusted.
36
+ * Satisfies BitGraph's atomic causality invariant when combined with a
37
+ * verifier that pins allowedMeasurements to a known-good enclave image.
38
+ * measurement MUST identify the attested enclave image.
39
+ * attestation SHOULD be present and verified by the relying party.
40
+ *
41
+ * IMPORTANT: Signing this field prevents downgrade tampering in transit
42
+ * but does NOT prevent a malicious adapter from lying about its tier.
43
+ * A verifier requiring "measured-tee" guarantees MUST independently
44
+ * validate measurement and attestation — not rely on this field alone.
45
+ */
46
+ export type EnforcementTier = "stub" | "hw-key" | "measured-tee";
47
+ /**
48
+ * A fully self-contained, verifiable commit proof.
49
+ *
50
+ * Two orthogonal facts are encoded:
51
+ *
52
+ * (A) Cryptographic fact — proven by signer.publicKeyB64 + signer.signatureB64
53
+ * Answers: "Who signed?" — objective, machine-checkable.
54
+ *
55
+ * (B) Enforcement fact — proven by environment.measurement + environment.attestation
56
+ * + verifier allowlist policy.
57
+ * Answers: "Under what enforced conditions was signing allowed?"
58
+ * Atomic causality lives here, not in (A).
59
+ *
60
+ * Signed body covers:
61
+ * version, artifact, commit, signer.publicKeyB64,
62
+ * environment.enforcement, environment.measurement,
63
+ * environment.attestation.format (when present),
64
+ * agency.actor identity (when agency is present)
65
+ *
66
+ * Outside the signature (advisory / vendor-signed / independently verifiable):
67
+ * signer.signatureB64, environment.attestation.reportB64,
68
+ * agency.authorization (P-256 signed, independently verifiable), metadata
69
+ */
70
+ export interface BitGraphProof {
71
+ /** Schema version. Hard-coded for forward-compatibility detection. */
72
+ version: "bitgraph/1";
73
+ /** Describes the committed artifact. */
74
+ artifact: {
75
+ /**
76
+ * Hash algorithm applied to the raw input bytes.
77
+ * Only "sha256" is defined for bitgraph/1.
78
+ */
79
+ hashAlg: "sha256";
80
+ /** Base64-standard (RFC 4648 §4) encoded SHA-256 digest of the input bytes. */
81
+ digestB64: string;
82
+ };
83
+ /** Describes the commit context that ensures uniqueness and ordering. */
84
+ commit: {
85
+ /** Base64-encoded boundary-fresh nonce produced by the host. */
86
+ nonceB64: string;
87
+ /**
88
+ * Monotonic counter value at commit time.
89
+ * Decimal string (no leading zeros unless value is "0", no leading +,
90
+ * ASCII digits only) to avoid IEEE-754 precision loss.
91
+ * Compared as BigInt by the verifier.
92
+ * Present only when the host implements nextCounter().
93
+ */
94
+ counter?: string;
95
+ /**
96
+ * Unix epoch milliseconds at commit time from a TEE-trusted clock.
97
+ * Advisory — software clocks may be skewed. Use counter for ordering.
98
+ * Present only when the host implements secureTime().
99
+ */
100
+ time?: number;
101
+ /**
102
+ * Base64-encoded hash of a previous BitGraphProof's canonical form,
103
+ * allowing callers to chain proofs into a verifiable sequence.
104
+ */
105
+ prevB64?: string;
106
+ /**
107
+ * Opaque identifier for the enclave lifecycle (epoch).
108
+ * Generated at enclave boot as SHA-256(publicKeyB64 + ":" + bootNonceB64).
109
+ * Unique per enclave lifecycle. Changes on every restart.
110
+ *
111
+ * Verifiers use this to detect epoch boundaries: when epochId changes,
112
+ * a new enclave lifecycle has begun (new keypair, counter may reset).
113
+ *
114
+ * Included in the signed body (via commit) — tamper-evident.
115
+ */
116
+ epochId?: string;
117
+ /**
118
+ * Counter value of the consumed slot allocation.
119
+ *
120
+ * When present, proves causal ordering: slotCounter < counter means
121
+ * the slot was allocated before the commit occurred. Combined with
122
+ * slotHashB64 and the embedded slotAllocation record, this provides
123
+ * structural evidence of nonce-first causality.
124
+ *
125
+ * Decimal string, compared as BigInt by the verifier.
126
+ */
127
+ slotCounter?: string;
128
+ /**
129
+ * SHA-256 hash of the canonical slot allocation body (Base64-encoded).
130
+ *
131
+ * Cryptographically binds the commit to the exact slot allocation record.
132
+ * The slot body is canonicalized (sorted keys, compact JSON, UTF-8) and
133
+ * hashed. This field is SIGNED (included in the signed body), so the
134
+ * Ed25519 commit signature covers the binding.
135
+ *
136
+ * A verifier reconstructs the slot body from slotAllocation, canonicalizes,
137
+ * hashes, and checks: SHA-256(canonicalize(slotBody)) === slotHashB64.
138
+ * This prevents slot swapping — any change to the slot record would
139
+ * break the commit signature.
140
+ */
141
+ slotHashB64?: string;
142
+ /**
143
+ * Epoch lineage link — present only on the FIRST proof of a new epoch.
144
+ *
145
+ * Establishes cryptographic succession: this epoch consumed the final
146
+ * proof of the previous epoch. The referenced proof's hash, signer,
147
+ * epochId, and counter are all included so a verifier can:
148
+ * 1. Confirm the predecessor proof is valid
149
+ * 2. Confirm prevProofHashB64 matches its canonical hash
150
+ * 3. Confirm prevPublicKeyB64 matches its signer
151
+ * 4. Detect forks (same predecessor consumed by multiple successors)
152
+ *
153
+ * New epochs continue lineage, not counters. Each epoch maintains its
154
+ * own local monotonic counter starting fresh.
155
+ *
156
+ * Single-successor invariant: a given (prevEpochId, prevCounter,
157
+ * prevProofHashB64) tuple MUST be consumed by AT MOST ONE successor
158
+ * epoch. Multiple epoch-genesis proofs referencing the same predecessor
159
+ * constitute a detectable fork.
160
+ */
161
+ epochLink?: {
162
+ /** EpochId of the predecessor epoch. */
163
+ prevEpochId: string;
164
+ /** Ed25519 public key of the predecessor epoch's signer. */
165
+ prevPublicKeyB64: string;
166
+ /** Final counter value from the predecessor epoch. */
167
+ prevCounter: string;
168
+ /** SHA-256 hash of the full predecessor proof (canonicalized). */
169
+ prevProofHashB64: string;
170
+ /** EpochId of THIS (successor) epoch — must match proof's commit.epochId. */
171
+ toEpochId: string;
172
+ /** Ed25519 public key of THIS (successor) epoch — must match proof's signer.publicKeyB64. */
173
+ toPublicKeyB64: string;
174
+ };
175
+ };
176
+ /**
177
+ * Cryptographic identity of the signer.
178
+ * Contains only the signing keypair — who signed.
179
+ * Enforcement context lives in environment, not here.
180
+ */
181
+ signer: {
182
+ /** Base64-encoded Ed25519 public key (32 bytes). */
183
+ publicKeyB64: string;
184
+ /**
185
+ * Base64-encoded Ed25519 signature (64 bytes) over the canonical
186
+ * serialization of the signed body.
187
+ * NOT included in the signed body itself.
188
+ */
189
+ signatureB64: string;
190
+ };
191
+ /**
192
+ * Enforcement context — under what conditions signing was allowed.
193
+ *
194
+ * enforcement and measurement are included in the signed body,
195
+ * making them tamper-evident. attestation.reportB64 is excluded
196
+ * from the signature because it is a vendor-signed document that
197
+ * self-authenticates.
198
+ */
199
+ environment: {
200
+ /**
201
+ * Self-reported enforcement tier.
202
+ * SIGNED — tamper-evident in transit but not self-authenticating.
203
+ * Verifiers MUST NOT treat this as sufficient evidence of tier.
204
+ */
205
+ enforcement: EnforcementTier;
206
+ /**
207
+ * Platform-specific measurement string.
208
+ * - stub: MAY be a synthetic sentinel
209
+ * - hw-key: SHOULD identify the key environment
210
+ * - measured-tee: MUST identify the attested enclave image
211
+ * SIGNED — pinned by verifier allowedMeasurements policy.
212
+ */
213
+ measurement: string;
214
+ /**
215
+ * Optional platform attestation report.
216
+ * If present, format MUST be a non-empty string.
217
+ * reportB64 is excluded from the signature (vendor-signed).
218
+ * attestation.format IS included in the signed body.
219
+ */
220
+ attestation?: {
221
+ /**
222
+ * Identifies the attestation document format.
223
+ * e.g. "aws-nitro", "sgx-dcap", "amd-sev-snp"
224
+ * SIGNED — prevents semantic ambiguity via format rewrite.
225
+ */
226
+ format: string;
227
+ /**
228
+ * Base64-encoded raw attestation report bytes.
229
+ * NOT signed — vendor-signed and self-authenticating.
230
+ * Platform-specific verifiers must parse and validate this.
231
+ */
232
+ reportB64: string;
233
+ };
234
+ };
235
+ /**
236
+ * Optional external timestamps (e.g. RFC 3161 TSA tokens).
237
+ * NOT included in the signed body. Independently verifiable.
238
+ *
239
+ * When present, each entry contains a TSA authority, ISO 8601 time,
240
+ * DER-encoded token (base64), digest algorithm, and the digest
241
+ * that was timestamped. The "artifact" timestamp covers the artifact
242
+ * digest; the "proof" timestamp covers the proof's canonical hash.
243
+ */
244
+ timestamps?: {
245
+ artifact?: {
246
+ authority: string;
247
+ time: string;
248
+ tokenB64: string;
249
+ digestAlg: string;
250
+ digestB64: string;
251
+ };
252
+ proof?: {
253
+ authority: string;
254
+ time: string;
255
+ tokenB64: string;
256
+ digestAlg: string;
257
+ digestB64: string;
258
+ };
259
+ };
260
+ /**
261
+ * Optional agency envelope — binds actor identity to this proof.
262
+ *
263
+ * When present, proves WHO authorized the commitment:
264
+ * - actor: device-bound identity (Secure Enclave P-256 key)
265
+ * - authorization: the possession commitment the actor signed
266
+ * (artifact hash + enclave-issued challenge + purpose + timestamp)
267
+ *
268
+ * Two independent signatures in the proof:
269
+ * - P-256 ECDSA (device Secure Enclave) → proves WHO authorized it
270
+ * - Ed25519 (Nitro Enclave) → proves it was committed inside the TEE
271
+ *
272
+ * The actor identity summary (keyId, publicKeyB64, algorithm, provider)
273
+ * is also included in the signed body (via SignedBody.actor), making it
274
+ * tamper-evident under the enclave's Ed25519 signature.
275
+ *
276
+ * The full authorization envelope (including the device's P-256 signature)
277
+ * lives here, outside the Ed25519 signed body — like attestation.reportB64,
278
+ * it is independently verifiable.
279
+ *
280
+ * NOT included in the Ed25519 signed body (independently verifiable).
281
+ */
282
+ agency?: AgencyEnvelope;
283
+ /**
284
+ * Embedded slot allocation record proving nonce-first causality.
285
+ *
286
+ * When present, this is a self-contained signed record that the enclave
287
+ * created BEFORE any artifact hash was known. The verifier checks:
288
+ * 1. Slot signature valid (enclave created it)
289
+ * 2. Slot body has no artifact hash (causal independence)
290
+ * 3. Slot nonce == commit nonce (binding)
291
+ * 4. Slot counter < commit counter (ordering)
292
+ * 5. Same key and epoch (same enclave)
293
+ *
294
+ * NOT included in the Ed25519 signed commit body — independently
295
+ * verifiable via its own Ed25519 signature (same pattern as
296
+ * attestation.reportB64 and agency.authorization).
297
+ */
298
+ slotAllocation?: SlotAllocation;
299
+ /**
300
+ * Optional policy binding — cryptographic proof that a specific policy
301
+ * document governed this action.
302
+ *
303
+ * Contains the SHA-256 hash of the policy document, plus optional
304
+ * human-readable name and version. INCLUDED in the Ed25519 signed body
305
+ * so the policy binding is tamper-evident and cryptographically sealed.
306
+ *
307
+ * Verifiers can confirm the policy hash matches a known-good policy
308
+ * document, establishing what rules the agent was operating under.
309
+ */
310
+ policy?: PolicyBinding;
311
+ /**
312
+ * Optional human-readable attribution claim.
313
+ *
314
+ * A free-form human claim associated with the artifact and commit event.
315
+ * INCLUDED in the Ed25519 signed body — cryptographically sealed and
316
+ * tamper-evident. Cannot be modified after the proof is created.
317
+ *
318
+ * This is a claim, not a guaranteed identity. It complements (does not
319
+ * replace) the cryptographic actor key in agency.
320
+ *
321
+ * All fields are optional. If no fields are provided, omit the object.
322
+ */
323
+ attribution?: Attribution;
324
+ /**
325
+ * Caller-supplied metadata key/value pairs.
326
+ * NOT included in the signed body. Treat as advisory only.
327
+ */
328
+ metadata?: Record<string, unknown>;
329
+ }
330
+ /**
331
+ * Policy applied during Constructor initialization.
332
+ */
333
+ export interface BitGraphPolicy {
334
+ /**
335
+ * If true, commits are rejected when host.nextCounter() is unavailable.
336
+ * Defaults to false (counter is advisory).
337
+ */
338
+ requireCounter?: boolean;
339
+ /**
340
+ * If true, commits are rejected when host.secureTime() is unavailable.
341
+ * Defaults to false.
342
+ */
343
+ requireTime?: boolean;
344
+ }
345
+ /**
346
+ * Constraints checked by the verifier against a BitGraphProof.
347
+ * All fields are optional; omitting a field skips that check.
348
+ *
349
+ * Trust model:
350
+ * - Cryptographic identity is proven by signature verification.
351
+ * - Enforcement guarantees are proven by measurement + attestation policy.
352
+ * - requireEnforcement alone is NOT sufficient for security — it must
353
+ * be combined with allowedMeasurements (and requireAttestation for
354
+ * measured-tee) to establish actual trust.
355
+ */
356
+ export interface VerificationPolicy {
357
+ /**
358
+ * Require a specific enforcement tier.
359
+ * MUST be combined with allowedMeasurements for security.
360
+ * This field is tamper-evident (signed) but not self-authenticating.
361
+ */
362
+ requireEnforcement?: EnforcementTier;
363
+ /**
364
+ * Accepted measurement strings. The proof's environment.measurement
365
+ * must exactly match one of the listed values.
366
+ * This is the primary trust anchor for enforcement verification.
367
+ */
368
+ allowedMeasurements?: string[];
369
+ /**
370
+ * Accepted public keys (Base64-encoded). The proof's
371
+ * signer.publicKeyB64 must exactly match one of the listed values.
372
+ */
373
+ allowedPublicKeys?: string[];
374
+ /**
375
+ * If true, the proof must contain environment.attestation.
376
+ * Required for full measured-tee verification.
377
+ */
378
+ requireAttestation?: boolean;
379
+ /**
380
+ * If provided, environment.attestation.format must match one of
381
+ * the listed format strings (e.g. ["aws-nitro", "sgx-dcap"]).
382
+ * Only checked when attestation is present.
383
+ */
384
+ requireAttestationFormat?: string[];
385
+ /**
386
+ * If set, proof.commit.counter must be >= this value (as BigInt).
387
+ * Decimal string, compared as BigInt to avoid precision loss.
388
+ */
389
+ minCounter?: string;
390
+ /**
391
+ * If set, proof.commit.counter must be <= this value (as BigInt).
392
+ * Use with minCounter to enforce a sliding replay-resistance window.
393
+ */
394
+ maxCounter?: string;
395
+ /**
396
+ * If set, proof.commit.time must be >= this Unix ms value.
397
+ */
398
+ minTime?: number;
399
+ /**
400
+ * If set, proof.commit.time must be <= this Unix ms value.
401
+ * Use with minTime to enforce a validity window.
402
+ */
403
+ maxTime?: number;
404
+ /**
405
+ * If true, proof.commit.epochId must be present.
406
+ * Required for production deployments using the epoch model.
407
+ * Verifiers should track epochId to detect epoch boundaries
408
+ * (enclave restarts) and cross-reference with an external
409
+ * monotonic anchor (e.g., DynamoDB) for cross-epoch continuity.
410
+ */
411
+ requireEpochId?: boolean;
412
+ /**
413
+ * If true, proof.agency must be present with a valid actor identity
414
+ * and authorization signature. The proof must answer WHO authorized
415
+ * the commitment, not just WHAT and WHERE.
416
+ */
417
+ requireActor?: boolean;
418
+ /**
419
+ * Accepted actor key IDs. The proof's agency.actor.keyId must
420
+ * exactly match one of the listed values.
421
+ * Key ID is hex(SHA-256(SPKI DER public key bytes)) — stable,
422
+ * deterministic, derived from the raw key material.
423
+ */
424
+ allowedActorKeyIds?: string[];
425
+ /**
426
+ * Accepted actor key providers. The proof's agency.actor.provider
427
+ * must exactly match one of the listed values.
428
+ * e.g. ["apple-secure-enclave", "android-strongbox", "webauthn"]
429
+ */
430
+ allowedActorProviders?: string[];
431
+ /**
432
+ * If true, proof must contain a valid slotAllocation proving
433
+ * nonce-first atomic causality (BitGraph causal commit model).
434
+ *
435
+ * When enabled, the verifier checks:
436
+ * - slotAllocation is present with valid Ed25519 signature
437
+ * - slotAllocation contains no artifact data (causal independence)
438
+ * - slotAllocation.nonceB64 === commit.nonceB64 (binding)
439
+ * - slotAllocation.counter < commit.counter (ordering)
440
+ * - slotAllocation.publicKeyB64 === signer.publicKeyB64 (same enclave)
441
+ * - slotAllocation.epochId === commit.epochId (same lifecycle)
442
+ *
443
+ * Required for verifiers that need to confirm true BitGraph causality,
444
+ * not just TEE-enforced signing with freshness.
445
+ */
446
+ requireSlot?: boolean;
447
+ }
448
+ /**
449
+ * Binds a BitGraphProof to the policy document that governed the action.
450
+ *
451
+ * The digestB64 is the SHA-256 hash of the raw policy document bytes
452
+ * (UTF-8 encoded). Any verifier can recompute this from the original
453
+ * policy document to confirm the binding.
454
+ *
455
+ * Included in the Ed25519 signed body — tamper-evident and
456
+ * cryptographically sealed by the signer.
457
+ */
458
+ export interface PolicyBinding {
459
+ /** SHA-256 hash of the policy document (Base64-standard, RFC 4648 §4). */
460
+ digestB64: string;
461
+ /**
462
+ * Digest of the BitGraph proof that committed this policy document.
463
+ * When present, the policy was authored through BitGraph (typically with
464
+ * biometric/passkey signing), making the authorship tamper-evident.
465
+ * Verifiers can look up this proof to confirm WHO authored the rules
466
+ * and WHEN they were signed — not just what the rules say.
467
+ */
468
+ authorProofDigestB64?: string;
469
+ /** Human-readable name of the policy (e.g. "Financial Agent"). */
470
+ name?: string;
471
+ /** Version identifier of the policy document. */
472
+ version?: string;
473
+ }
474
+ /**
475
+ * Human-readable attribution claim associated with the artifact.
476
+ *
477
+ * All fields are optional. Included in the Ed25519 signed body so that
478
+ * the text is cryptographically sealed and tamper-evident.
479
+ *
480
+ * This is a claim, not a guaranteed identity. It complements the
481
+ * cryptographic actor key in agency.
482
+ */
483
+ export interface Attribution {
484
+ /** Human name of the person or entity making the claim. */
485
+ name?: string;
486
+ /** Short description of the claim (e.g. "Original capture"). */
487
+ title?: string;
488
+ /** Free-form message associated with the artifact (e.g. "Shot at sunset in Buffalo."). */
489
+ message?: string;
490
+ }
491
+ /**
492
+ * Actor identity — a device-bound key that identifies WHO authorized
493
+ * a commitment.
494
+ *
495
+ * This structure appears in two places:
496
+ * 1. SignedBody.actor — signed by the TEE's Ed25519 key (tamper-evident)
497
+ * 2. BitGraphProof.agency.actor — in the full agency envelope
498
+ *
499
+ * The keyId is deterministic: hex(SHA-256(SPKI DER public key bytes)).
500
+ * Any verifier can recompute it from the raw public key to confirm
501
+ * the binding.
502
+ */
503
+ export interface ActorIdentity {
504
+ /** Stable device key ID: hex(SHA-256(SPKI DER public key bytes)). */
505
+ keyId: string;
506
+ /** Base64 SPKI DER P-256 public key (standard format, any platform can parse). */
507
+ publicKeyB64: string;
508
+ /** Signature algorithm the device used. */
509
+ algorithm: "ES256";
510
+ /** Key origin: "apple-secure-enclave", "android-strongbox", "webauthn". */
511
+ provider: string;
512
+ }
513
+ /**
514
+ * The canonical payload that the actor's device signs.
515
+ *
516
+ * Serialized as canonical JSON (sorted keys, compact, UTF-8) for signing.
517
+ * signatureB64 is excluded from the signed bytes (it IS the signature).
518
+ *
519
+ * Fields:
520
+ * - purpose: domain separation — prevents cross-context signature reuse
521
+ * - actorKeyId: must match actor.keyId (binds signature to specific key)
522
+ * - artifactHash: must match proof.artifact.digestB64 (binds to specific artifact)
523
+ * - challenge: enclave-issued nonce (prevents replay)
524
+ * - timestamp: Unix epoch ms (enclave checks freshness)
525
+ */
526
+ export interface AuthorizationPayload {
527
+ /** Domain separation: prevents cross-context signature reuse. */
528
+ purpose: "bitgraph/commit-authorize/v1";
529
+ /** Must match actor.keyId. */
530
+ actorKeyId: string;
531
+ /** Base64 SHA-256 of artifact — must match proof.artifact.digestB64. */
532
+ artifactHash: string;
533
+ /** Enclave-issued challenge (prevents replay). */
534
+ challenge: string;
535
+ /** Unix epoch ms — enclave checks freshness. */
536
+ timestamp: number;
537
+ /**
538
+ * Optional protocol version. When present, included in the canonical
539
+ * JSON payload that is P-256-signed. Allows versioning the authorization
540
+ * format while maintaining backward compatibility (old payloads without
541
+ * this field remain valid).
542
+ */
543
+ protocolVersion?: string;
544
+ }
545
+ /**
546
+ * WebAuthn authorization payload — sent when the device signs via
547
+ * navigator.credentials.get() (passkey / Face ID / Touch ID).
548
+ *
549
+ * WebAuthn signs `authenticatorData || SHA-256(clientDataJSON)`, not
550
+ * arbitrary data. The enclave-issued challenge is embedded in
551
+ * clientDataJSON.challenge. The enclave must verify the WebAuthn
552
+ * signature over the standard WebAuthn signed data format.
553
+ */
554
+ export interface WebAuthnAuthorization {
555
+ /** Domain separation — same as direct. */
556
+ purpose: "bitgraph/commit-authorize/v1";
557
+ /** Discriminator for verification path. */
558
+ format: "webauthn";
559
+ /** Must match actor.keyId. */
560
+ actorKeyId: string;
561
+ /** Base64 SHA-256 of artifact — must match proof.artifact.digestB64. */
562
+ artifactHash: string;
563
+ /** Enclave-issued challenge (base64). Embedded in clientDataJSON. */
564
+ challenge: string;
565
+ /** Unix epoch ms — checked for freshness. */
566
+ timestamp: number;
567
+ /** Base64-encoded raw authenticator data bytes. */
568
+ authenticatorDataB64: string;
569
+ /** Full clientDataJSON string (UTF-8). Contains challenge, origin, type. */
570
+ clientDataJSON: string;
571
+ /** Base64 DER ECDSA P-256 signature from the authenticator. */
572
+ signatureB64: string;
573
+ }
574
+ /**
575
+ * Full agency envelope — lives in BitGraphProof.agency.
576
+ *
577
+ * Contains the actor identity and the authorization payload
578
+ * (including the device's P-256 signature). Independently verifiable:
579
+ * any verifier can check the P-256 signature over the authorization
580
+ * payload without needing any server or API.
581
+ *
582
+ * Two authorization formats:
583
+ * - Direct: P-256 signature over canonical JSON (native apps, test scripts)
584
+ * - WebAuthn: Standard WebAuthn assertion (browser passkeys, Face ID / Touch ID)
585
+ */
586
+ export interface AgencyEnvelope {
587
+ /** Actor identity (matches SignedBody.actor when present). */
588
+ actor: ActorIdentity;
589
+ /** The possession commitment the actor signed. */
590
+ authorization: (AuthorizationPayload & {
591
+ /**
592
+ * Base64 DER ECDSA signature over canonical JSON of the
593
+ * AuthorizationPayload (excluding signatureB64 itself).
594
+ * P-256 / ES256 — verifiable with actor.publicKeyB64.
595
+ */
596
+ signatureB64: string;
597
+ }) | WebAuthnAuthorization;
598
+ /**
599
+ * Present on batch proofs. The P-256 signature binds to the first digest;
600
+ * batchContext maps every proof in the batch back to that authorization.
601
+ */
602
+ batchContext?: {
603
+ batchSize: number;
604
+ batchIndex: number;
605
+ batchDigests: string[];
606
+ };
607
+ }
608
+ /**
609
+ * Signed slot allocation record.
610
+ *
611
+ * Created by the enclave's allocateSlot endpoint BEFORE any artifact hash
612
+ * is known. The slot body deliberately contains NO artifact data — this is
613
+ * the structural proof of causal independence.
614
+ *
615
+ * The enclave signs this record at allocation time and stores the nonce as
616
+ * a single-use resource in pendingSlots. When a client later calls commit
617
+ * with the slotId, the enclave consumes the slot and embeds this record in
618
+ * the proof. A verifier can then confirm:
619
+ *
620
+ * 1. The slot signature is valid (enclave created it)
621
+ * 2. The slot body contains no artifact hash (causal independence)
622
+ * 3. SHA-256(canonicalize(slotBody)) === commit.slotHashB64 (signed binding)
623
+ * 4. slotAllocation.nonceB64 === commit.nonceB64 (nonce binding)
624
+ * 5. slotAllocation.counter < commit.counter (ordering)
625
+ * 6. Same publicKeyB64 and epochId (same enclave lifecycle)
626
+ *
627
+ * Together these checks prove the nonce existed before the artifact was
628
+ * bound to it — the BitGraph atomic causality invariant.
629
+ */
630
+ export interface SlotAllocation {
631
+ /** Schema version for slot records. Domain separation from proof bodies. */
632
+ version: "bitgraph/slot/1";
633
+ /** NSM-generated nonce. Becomes commit.nonceB64 when consumed. */
634
+ nonceB64: string;
635
+ /** Monotonic counter at allocation time. Must be < commit counter. */
636
+ counter: string;
637
+ /** Advisory timestamp (Unix epoch ms) at allocation time. Optional — BitGraph is causal, not temporal. */
638
+ time?: number;
639
+ /** Enclave lifecycle identifier. Must match commit.epochId. */
640
+ epochId: string;
641
+ /** Enclave Ed25519 public key. Must match signer.publicKeyB64. */
642
+ publicKeyB64: string;
643
+ /** Chain isolation identifier. Omitted for the default "global" chain. */
644
+ chainId?: string;
645
+ /** Ed25519 signature over canonical slot body (all fields above). */
646
+ signatureB64: string;
647
+ }
648
+ /**
649
+ * The object that is serialized and signed.
650
+ * Constructed internally by Constructor.commit() and reconstructed by
651
+ * verify() for signature validation.
652
+ *
653
+ * Exported so external adapters can construct test proofs without
654
+ * re-implementing the signing body layout.
655
+ *
656
+ * Signed fields:
657
+ * version, artifact, commit, publicKeyB64,
658
+ * enforcement, measurement, attestationFormat (when present),
659
+ * actor (when agency is present),
660
+ * attribution (when provided)
661
+ */
662
+ export interface SignedBody {
663
+ version: "bitgraph/1";
664
+ artifact: BitGraphProof["artifact"];
665
+ commit: BitGraphProof["commit"];
666
+ /** Public key included to bind cryptographic identity to the body. */
667
+ publicKeyB64: string;
668
+ /** Enforcement tier — signed to prevent downgrade attacks. */
669
+ enforcement: EnforcementTier;
670
+ /** Measurement — primary trust anchor for enforcement verification. */
671
+ measurement: string;
672
+ /**
673
+ * Attestation format string — signed to prevent semantic ambiguity.
674
+ * Present only when environment.attestation is present.
675
+ * reportB64 is intentionally excluded (vendor-signed).
676
+ */
677
+ attestationFormat?: string;
678
+ /**
679
+ * Actor identity summary — included in the signed body when agency
680
+ * is present.
681
+ *
682
+ * Follows the same pattern as attestationFormat: identity summary is
683
+ * signed (tamper-evident under Ed25519), while the full signature
684
+ * envelope (agency.authorization.signatureB64) lives outside the
685
+ * signed body and is independently verifiable.
686
+ *
687
+ * The TEE verifies the actor's P-256 signature BEFORE including this
688
+ * in the signed body, so its presence means the TEE confirmed the
689
+ * actor authorized this specific commitment.
690
+ */
691
+ actor?: ActorIdentity;
692
+ /**
693
+ * Policy binding — sealed into the signed body.
694
+ * Present only when a policy document was active at commit time.
695
+ * Canonical serialization includes this when present.
696
+ */
697
+ policy?: PolicyBinding;
698
+ /**
699
+ * Human-readable attribution claim — sealed into the signed body.
700
+ * Present only when the user provided attribution fields at commit time.
701
+ * Canonical serialization includes this when present.
702
+ */
703
+ attribution?: Attribution;
704
+ }
705
+ //# sourceMappingURL=types.d.ts.map