@adastracomputing/ink 0.1.0-alpha.1 → 0.1.0-alpha.3

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/docs/maturity.md CHANGED
@@ -17,7 +17,7 @@
17
17
  implementations should report discrepancies as issues.
18
18
  - The protocol is in use by one production integrator (Tulpa). That is
19
19
  one data point, not a guarantee of robustness at scale.
20
- - The reference implementation in `src/` runs on any runtime providing
20
+ - The library in `src/` runs on any runtime providing
21
21
  standard Web Crypto (`crypto.subtle`) and `fetch`, modern Node, Deno,
22
22
  Bun, and edge runtimes. Browser use is feasible but not exercised by
23
23
  the maintainers.
@@ -55,7 +55,7 @@ Pre-1.0 releases follow `0.Y.Z` semantics:
55
55
 
56
56
  - `0.Y.0`, Minor version bump indicates a wire-format change. Receivers
57
57
  must support at least one prior minor during a transition window.
58
- - `0.Y.Z` (Z > 0), Patch bumps fix bugs in the reference implementation
58
+ - `0.Y.Z` (Z > 0), Patch bumps fix bugs in the library
59
59
  and update test vectors where needed. They do not change wire format.
60
60
 
61
61
  Breaking changes before v1.0 will be announced in the repository
@@ -71,7 +71,7 @@ be a real incident:
71
71
  falls inside the in-scope protections and you accept the out-of-scope
72
72
  limits.
73
73
  2. Run `../test-vectors/*` against your implementation.
74
- 3. Fuzz your envelope parser. The reference implementation's tests are
74
+ 3. Fuzz your envelope parser. The library's tests are
75
75
  not a substitute.
76
76
  4. Pen-test the rotation and revocation flows specifically. The
77
77
  authority rule is the single most security-sensitive piece and the
@@ -80,7 +80,7 @@ bounds the damage window but does not eliminate it. Key custody is out of
80
80
  scope.
81
81
 
82
82
  ### Malicious marketplace extensions (if you integrate one)
83
- The reference implementation does not include an extension/marketplace
83
+ The library does not include an extension/marketplace
84
84
  layer. A product that integrates INK and adds a delegation-token layer
85
85
  (for third-party agents to act on behalf of users) must design its own
86
86
  trust model for the marketplace, manifest review, and capability
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@adastracomputing/ink",
3
- "version": "0.1.0-alpha.1",
4
- "description": "Reference implementation and specification of the INK (Inter-agent Networking Kernel) protocol",
3
+ "version": "0.1.0-alpha.3",
4
+ "description": "Library and specification for the INK (Inter-agent Networking Kernel) protocol",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "author": "Ad Astra Computing Inc.",
7
7
  "repository": {
@@ -26,8 +26,12 @@
26
26
  "engines": {
27
27
  "node": ">=22"
28
28
  },
29
+ "bin": {
30
+ "ink": "./bin/ink.mjs"
31
+ },
29
32
  "files": [
30
33
  "src/",
34
+ "bin/",
31
35
  "specs/",
32
36
  "docs/",
33
37
  "test-vectors/",
@@ -67,6 +71,6 @@
67
71
  "ed25519",
68
72
  "atproto",
69
73
  "agent-to-agent",
70
- "reference-implementation"
74
+ "transparency-log"
71
75
  ]
72
76
  }
@@ -461,9 +461,9 @@ The audit service:
461
461
  1. Accepts signed `InkAuditEvent` submissions from agents
462
462
  2. Appends them to a **Merkle tree** (not just a hash chain, enables efficient inclusion proofs)
463
463
  3. Returns a **signed inclusion receipt** proving the event was recorded at a specific tree position and timestamp
464
- 4. Serves **inclusion proofs** and **consistency proofs** on demand
464
+ 4. Serves **inclusion proofs** on demand (per-submission via the inclusion receipt and per-query via the signed `audit_query_response` envelope). **Consistency proofs** between two arbitrary checkpoints are not in scope for alpha.3; consistency-proof verification against external `tlog-witness` cosigners (§7.0) is the alpha.3 mitigation against split-view attacks.
465
465
 
466
- The service CANNOT forge events (they carry the submitting agent's Ed25519 signature). It CAN prove:
466
+ The service CANNOT forge events that verifiers will accept, because every returned event carries the submitting agent's Ed25519 `agentSignature` and §7.3 verifiers re-check it against the agent's published keys. A witness that commits a fabricated event_json into its Merkle tree can produce a valid inclusion proof, but verifiers will reject the response when the agent signature fails to validate. (Verifiers that walk Merkle proofs without checking `agentSignature` lose this guarantee; see §7.5.) The service CAN prove:
467
467
  - That a specific event was submitted at a specific time (inclusion)
468
468
  - That the log is append-only and no events have been removed (consistency)
469
469
  - That two parties submitted conflicting events for the same message (conflict detection)
@@ -531,41 +531,66 @@ Authorization: INK-Ed25519 <signature>
531
531
  }
532
532
  ```
533
533
 
534
- **Response includes Merkle inclusion proofs:**
534
+ **Response includes Merkle inclusion proofs and is signed by the witness:**
535
535
 
536
536
  ```json
537
537
  {
538
538
  "protocol": "ink/0.1",
539
- "type": "network.tulpa.audit_response",
539
+ "type": "network.tulpa.audit_query_response",
540
+ "serviceDid": "did:web:witness.example.com",
540
541
  "messageId": "msg-123",
541
- "events": [ /* InkAuditEvent[] from all agents */ ],
542
+ "requester": "did:plc:requester",
543
+ "events": [ /* InkAuditEvent[] visible to the requester */ ],
542
544
  "proofs": [
543
545
  {
544
546
  "eventId": "01JBTEST0001",
545
547
  "leafIndex": 48290,
546
- "inclusionPath": ["<hash>", "<hash>", "..."],
547
- "treeSize": 48291,
548
- "rootHash": "<SHA-256 hex>"
548
+ "inclusionProof": ["<hash>", "<hash>", "..."]
549
549
  }
550
550
  ],
551
- "serviceSignature": "<Ed25519 over JCS(response)>"
551
+ "treeSize": 48291,
552
+ "rootHash": "<SHA-256 hex of Merkle tree root at response time>",
553
+ "timestamp": "2026-03-19T13:00:01Z",
554
+ "serviceSignature": "<Ed25519, see canonical format below>"
552
555
  }
553
556
  ```
554
557
 
558
+ **Canonical signature format.** `serviceSignature` is an Ed25519 signature over the bytes:
559
+
560
+ ```
561
+ "ink/audit-query-response/v1\n" || JCS(response-fields-without-serviceSignature)
562
+ ```
563
+
564
+ The signed payload binds the witness's `serviceDid`, the `messageId` requested, the authenticated `requester` whose access-control scope produced the result, every returned event, every inclusion proof, the witness's `treeSize` and `rootHash` at response time and the `timestamp`. The `proofs` array has one entry per event, keyed by `eventId`; verifiers MUST reject if proofs do not match events one-to-one. `treeSize` and `rootHash` apply uniformly to every proof. The `requester` binding prevents cross-requester replay: a witness response generated for Alice cannot be presented to Bob as Bob's authoritative view of the same `messageId`. Verifiers MUST check `requester` equals the locally authenticated requester before treating the response as their own scoped view.
565
+
566
+ Per-event scope: a signed envelope binds `messageId` and `requester` but says nothing about the event objects until verifiers look inside them. To prevent a witness or a tampering intermediary from smuggling out-of-scope events into a signed response, verifiers MUST reject any response where, for any returned event, `event.messageId` differs from the envelope `messageId`, OR the envelope `requester` is neither `event.agentId` nor `event.counterpartyId`. Witnesses SHOULD reject the same conditions at signing time as defense in depth against storage corruption.
567
+
568
+ Empty-log responses: a witness that has not yet committed any leaves reports `treeSize: 0` and `rootHash` equal to SHA-256 of the empty string (`e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`). A signed response with `treeSize: 0` is legitimate but MUST also have empty `events`, empty `proofs` and the empty-tree `rootHash`. Verifiers MUST reject any `treeSize: 0` response that deviates from this shape.
569
+
570
+ Per-event agent signatures: Merkle validity alone does NOT prove a returned event was produced by the agent named in `event.agentId`. A witness could in principle commit a fabricated event_json that is not a real `InkAuditEvent`. Every returned event MUST therefore include its `agentSignature` field. Verifiers MUST resolve the submitting agent's published Ed25519 keys (via Agent Card §2) and verify `agentSignature` on every event in addition to walking the Merkle proof. A response that omits `agentSignature` on any event MUST be rejected as structurally invalid.
571
+
572
+ Truncation: witnesses MUST NOT silently sign a partial result. If the requester's visible event set for a `messageId` exceeds the witness's response cap, the witness MUST return an unsigned error response (HTTP 413). A signed response is, by definition, a complete enumeration of the requester's visible events for that `messageId` at `(treeSize, rootHash)`.
573
+
574
+ Determinism: witnesses MUST emit `events` and matching `proofs` in a stable, deterministic order so verifiers can reproduce the signed bytes from the underlying records.
575
+
576
+ Leaf hash: each event's Merkle leaf hash is `SHA-256(0x00 || JCS(event-without-agentSignature))`. The leading `0x00` byte is the RFC 6962 leaf-domain-separation tag; internal Merkle nodes use `0x01 || left || right`. Verifiers MUST rehash the returned `event` object themselves (stripping `agentSignature`, then JCS, then SHA-256 with the `0x00` prefix) and use that hash as the leaf input to `inclusionProof`. They MUST NOT trust any leaf-hash value supplied by the witness alongside the event. Walking the proof from this computed leaf hash up through `inclusionProof` MUST reach the top-level `rootHash` per the proof construction in §7.2. The INK library exposes this exact computation as `computeAuditMerkleLeafHash`; it is distinct from `computeEventHash`, which is the unprefixed SHA-256 used for `previousEventHash` chain linkage and MUST NOT be used as the Merkle leaf input.
577
+
555
578
  #### 7.4 Access Control
556
579
 
557
580
  The audit service operates under **access-controlled transparency** (per SCITT):
558
581
  - Events are tagged with the `messageId` and the DIDs of sender/recipient
559
- - Only the sender, recipient or a party with a valid delegation chain (§ INK Authorization Chain) can query events for a given `messageId`
582
+ - Only the sender or recipient (i.e. an event's own `agentId` or `counterpartyId`) can query events for a given `messageId`. The witness MUST refuse to serve a row to any other requester
560
583
  - The service verifies the requester's identity via INK auth (§3.3) before serving events
561
- - The Merkle tree structure is public (anyone can verify consistency proofs) but event contents are access-controlled
584
+ - The Merkle tree structure is public: anyone can verify inclusion proofs against signed checkpoints and, where consistency-proof endpoints are deployed, cross-check that checkpoints are append-only. Event contents remain access-controlled
585
+
586
+ Delegated queries (where a third-party agent queries events on behalf of a principal via an INK Authorization Chain) are not in scope for alpha.3. A future revision will define the additional envelope fields the witness signs to bind the effective principal alongside the immediate requester, and verifiers will be updated accordingly. Until then, conformant witnesses MUST treat the per-event scope rule in §7.3 as authoritative: a returned event's `agentId` or `counterpartyId` MUST equal the response `requester`.
562
587
 
563
588
  This follows SCITT's model: the transparency guarantee (append-only, no suppression) is public, but the data itself is private.
564
589
 
565
590
  #### 7.5 Trust Model
566
591
 
567
592
  The audit service is a **semi-trusted witness**, not an arbiter:
568
- - It CANNOT forge events (Ed25519 signatures from agents)
593
+ - It CANNOT forge events that verifiers will accept, because verifiers re-check `event.agentSignature` against the agent's published Ed25519 keys (§7.3). A witness that commits a fabricated event_json into its Merkle tree can produce a valid inclusion proof, but the per-event agent-signature check fails and the response is rejected. Verifiers that walk the proof without checking `agentSignature` lose this guarantee.
569
594
  - It CANNOT modify events without breaking Merkle proofs
570
595
  - It CAN suppress events by refusing to include them (detectable via consistency proofs between submissions)
571
596
  - It CAN be unavailable (agents fall back to bilateral exchange)
@@ -16,7 +16,7 @@ This checklist lets an independent implementer verify INK conformance without re
16
16
  - **SHOULD**, recommended; deviations require justification
17
17
  - **MAY**, truly optional; advertised via capability
18
18
 
19
- **Status column** applies to the Tulpa reference implementation:
19
+ **Status column** applies to the Tulpa implementation:
20
20
  - **Required**, part of the v1 wire contract
21
21
  - **Optional**, capability-gated, not assumed
22
22
  - **Extension**, defined but not required for base interop
@@ -145,6 +145,14 @@ This checklist lets an independent implementer verify INK conformance without re
145
145
  | W6 | Checkpoint: C2SP tlog-checkpoint format at `GET /ink/v1/checkpoint` | SHOULD | Optional | Auditability §7 |, | `witness/witness/test/endpoints.test.ts (witness repo)` |
146
146
  | W7 | Transport auth on submit: dual signature (transport + event) | MUST | Optional | Auditability §7 | `witness.json` | `witness/witness/test/endpoints.test.ts (witness repo)` |
147
147
  | W8 | Submit includes `signingKeyId` in transport auth | SHOULD | Required | Key Rotation Phase 3 |, | `test/ink-key-rotation.test.ts` |
148
+ | W9 | Query response is the signed `network.tulpa.audit_query_response` envelope binding `serviceDid`, `messageId`, `requester`, `events`, `proofs`, `treeSize`, `rootHash`, `timestamp` | MUST | Optional | Auditability §7.3 | `witness.json` | `test/audit-query-response.test.ts`, `test/verify-audit-query-response.test.ts` |
149
+ | W10 | Per-event Merkle proof rule: leaf = `SHA-256(0x00 \|\| JCS(event-without-agentSignature))` (RFC 6962) | MUST | Optional | Auditability §7.3 | `witness.json` | `test/merkle-leaf-hash.test.ts` |
150
+ | W11 | Per-event scope: `event.messageId == envelope.messageId` AND `envelope.requester ∈ {event.agentId, event.counterpartyId}` | MUST | Optional | Auditability §7.3, §7.4 |, | `test/verify-audit-query-response.test.ts` |
151
+ | W12 | Deterministic result-set ordering so signed bytes are reproducible | MUST | Optional | Auditability §7.3 |, | `witness/witness/test/security-round12.test.ts (witness repo)` |
152
+ | W13 | Fail-closed on truncation: refuse to sign a partial result; return unsigned 413 | MUST | Optional | Auditability §7.3 |, | `witness/witness/test/security-round12.test.ts (witness repo)` |
153
+ | W14 | Fail-closed on storage integrity (event_hash mismatch, missing Merkle node, column-vs-event_json drift): HTTP 500, no signed response | MUST | Optional | Auditability §7.3 |, | `witness/witness/test/security-round12.test.ts (witness repo)` |
154
+ | W15 | Empty-log response: `treeSize == 0` MUST have empty `events`, empty `proofs` and canonical empty-tree `rootHash` | MUST | Optional | Auditability §7.3 |, | `test/verify-audit-query-response.test.ts` |
155
+ | W16 | Every returned event MUST include `agentSignature`; verifiers MUST verify it against the agent's published keys (witness Merkle validity does not prove agent provenance) | MUST | Optional | Auditability §7.3, §7.5 |, | `test/verify-audit-query-response.test.ts` |
148
156
 
149
157
  ---
150
158