@zanii/core 0.2.0 → 0.3.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 CHANGED
@@ -1,64 +1,72 @@
1
- # @zanii/core
2
-
3
- The Zanii protocol as pure functions — **no I/O, no network, no trusted party.**
4
- Agent identities (`did:key`), scoped delegation certificates, signed action
5
- receipts, RFC 6962 Merkle transparency-log proofs, and self-contained audit
6
- bundles. Everything here is deterministic; use it to build proofs, or to
7
- **verify** them independently of any Zanii server.
8
-
9
- If you want to instrument a live agent (batching, HTTP ingest, tool wrapping),
10
- use [`@zanii/sdk`](https://www.npmjs.com/package/@zanii/sdk), which builds on
11
- this.
12
-
13
- ```sh
14
- npm install @zanii/core
15
- ```
16
-
17
- ## Verify a receipt, offline
18
-
19
- ```ts
20
- import {
21
- generateKeypair,
22
- createCert,
23
- createReceipt,
24
- hashPayload,
25
- verifyReceipt,
26
- } from '@zanii/core';
27
-
28
- const owner = generateKeypair();
29
- const agent = generateKeypair();
30
- const cert = createCert(
31
- { issuer: owner.did, subject: agent.did, scopes: ['crm.*'], exp: '2027-01-01T00:00:00Z' },
32
- owner.privateKey,
33
- );
34
- const receipt = createReceipt(
35
- {
36
- agentId: agent.did,
37
- delegation: [cert],
38
- action: 'tool_call',
39
- target: 'crm.lookup',
40
- payloadHash: hashPayload(JSON.stringify({ email: 'a@b.co' })),
41
- ts: new Date().toISOString(),
42
- prev: null,
43
- },
44
- agent.privateKey,
45
- );
46
-
47
- // Checks the signature, the delegation chain, and that the action is in scope —
48
- // with no server and no trust.
49
- const result = verifyReceipt(receipt);
50
- if (!result.ok) throw new Error(result.error);
51
- ```
52
-
53
- `verifyAuditBundle(bundle)` does the same for a complete exported history at
54
- once: every receipt's signature and Merkle inclusion, the per-agent hash chain,
55
- revocations, and on-chain anchor consistency.
56
-
57
- ## Links
58
-
59
- - **Docs & concepts** — https://ledger.zanii.agency/docs
60
- - **Live transparency log** — https://ledger.zanii.agency
61
-
62
- ## License
63
-
64
- Apache-2.0.
1
+ # @zanii/core
2
+
3
+ The Zanii protocol as pure functions — **no I/O, no network, no trusted party.**
4
+ Agent identities (`did:key`), scoped delegation certificates, signed action
5
+ receipts, RFC 6962 Merkle transparency-log proofs, and self-contained audit
6
+ bundles. Everything here is deterministic; use it to build proofs, or to
7
+ **verify** them independently of any Zanii server.
8
+
9
+ If you want to instrument a live agent (batching, HTTP ingest, tool wrapping),
10
+ use [`@zanii/sdk`](https://www.npmjs.com/package/@zanii/sdk), which builds on
11
+ this.
12
+
13
+ ```sh
14
+ npm install @zanii/core
15
+ ```
16
+
17
+ ## Verify a receipt, offline
18
+
19
+ ```ts
20
+ import {
21
+ generateKeypair,
22
+ createCert,
23
+ createReceipt,
24
+ hashPayload,
25
+ verifyReceipt,
26
+ } from '@zanii/core';
27
+
28
+ const owner = generateKeypair();
29
+ const agent = generateKeypair();
30
+ const cert = createCert(
31
+ { issuer: owner.did, subject: agent.did, scopes: ['crm.*'], exp: '2027-01-01T00:00:00Z' },
32
+ owner.privateKey,
33
+ );
34
+ const receipt = createReceipt(
35
+ {
36
+ agentId: agent.did,
37
+ delegation: [cert],
38
+ action: 'tool_call',
39
+ target: 'crm.lookup',
40
+ payloadHash: hashPayload(JSON.stringify({ email: 'a@b.co' })),
41
+ ts: new Date().toISOString(),
42
+ prev: null,
43
+ },
44
+ agent.privateKey,
45
+ );
46
+
47
+ // Checks the signature, the delegation chain, and that the action is in scope —
48
+ // with no server and no trust.
49
+ const result = verifyReceipt(receipt);
50
+ if (!result.ok) throw new Error(result.error);
51
+ ```
52
+
53
+ `verifyAuditBundle(bundle)` does the same for a complete exported history at
54
+ once: every receipt's signature and Merkle inclusion, the per-agent hash chain,
55
+ revocations, and on-chain anchor consistency.
56
+
57
+ ## Links
58
+
59
+ - **Docs & concepts** — https://ledger.zanii.agency/docs
60
+ - **Live transparency log** — https://ledger.zanii.agency
61
+
62
+ ## Changelog
63
+
64
+ - **0.3.0** — `saltedPayloadHash`/`verifyPayload`, `createConfirmation`/`verifyConfirmation`, `createCoSignature`/`verifyCoSignature`, and optional receipt provenance fields (`runtime_hash`/`model_id`/`manifest_hash`).
65
+ - **0.2.0** — version bump in lockstep with the package family (no API changes).
66
+ - **0.1.0** — initial release: `did:key` identity, scoped/expiring delegation, signed
67
+ hash-chained receipts, RFC 6962 Merkle inclusion + consistency proofs, signed tree
68
+ heads, audit-bundle verification, and cross-org (A2A) receipts.
69
+
70
+ ## License
71
+
72
+ Apache-2.0.
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Owner confirmation of an irreversible action (SPEC §13 / Article VI).
3
+ *
4
+ * The human owner signs the exact action hash with their `did:key`. This is the
5
+ * cryptographic evidence a person confirmed — replacing an in-memory "yes" that
6
+ * proves nothing. Recorded as its own `action_confirmation` receipt so a dispute
7
+ * ("did the client actually approve this payment?") has a verifiable answer.
8
+ */
9
+ export interface ActionConfirmation {
10
+ v: 1;
11
+ type: 'action_confirmation';
12
+ /** The owner's `did:key`. */
13
+ owner_id: string;
14
+ /** `sha256:…` hash of the exact action `{tool, args}` being confirmed. */
15
+ action_hash: string;
16
+ confirmed_at: string;
17
+ /** Ed25519 by the owner over JCS of the confirmation without `sig`. */
18
+ sig: string;
19
+ }
20
+ /** Owner signs an action hash. Only the owner's key can produce this. */
21
+ export declare function createConfirmation(fields: {
22
+ ownerId: string;
23
+ actionHash: string;
24
+ confirmedAt: string;
25
+ }, ownerPrivateKey: Uint8Array): ActionConfirmation;
26
+ /** Verify a confirmation's signature against the owner DID it names. */
27
+ export declare function verifyConfirmation(c: ActionConfirmation): boolean;
28
+ //# sourceMappingURL=confirmation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirmation.d.ts","sourceRoot":"","sources":["../src/confirmation.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,CAAC,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,qBAAqB,CAAC;IAC5B,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAC;CACb;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAChC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EACpE,eAAe,EAAE,UAAU,GAC1B,kBAAkB,CAUpB;AAED,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAWjE"}
@@ -0,0 +1,32 @@
1
+ import { ed25519 } from '@noble/curves/ed25519';
2
+ import { canonicalBytes, decodeSig, encodeSig } from './encoding.js';
3
+ import { publicKeyFromDid } from './keys.js';
4
+ /** Owner signs an action hash. Only the owner's key can produce this. */
5
+ export function createConfirmation(fields, ownerPrivateKey) {
6
+ const unsigned = {
7
+ v: 1,
8
+ type: 'action_confirmation',
9
+ owner_id: fields.ownerId,
10
+ action_hash: fields.actionHash,
11
+ confirmed_at: fields.confirmedAt,
12
+ };
13
+ const sig = ed25519.sign(canonicalBytes(unsigned), ownerPrivateKey);
14
+ return { ...unsigned, sig: encodeSig(sig) };
15
+ }
16
+ /** Verify a confirmation's signature against the owner DID it names. */
17
+ export function verifyConfirmation(c) {
18
+ if (c?.v !== 1 || c.type !== 'action_confirmation')
19
+ return false;
20
+ const pub = publicKeyFromDid(c.owner_id);
21
+ const sig = decodeSig(c.sig);
22
+ if (!pub || !sig)
23
+ return false;
24
+ const { sig: _omitted, ...unsigned } = c;
25
+ try {
26
+ return ed25519.verify(sig, canonicalBytes(unsigned), pub);
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ //# sourceMappingURL=confirmation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirmation.js","sourceRoot":"","sources":["../src/confirmation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAsB7C,yEAAyE;AACzE,MAAM,UAAU,kBAAkB,CAChC,MAAoE,EACpE,eAA2B;IAE3B,MAAM,QAAQ,GAAG;QACf,CAAC,EAAE,CAAU;QACb,IAAI,EAAE,qBAA8B;QACpC,QAAQ,EAAE,MAAM,CAAC,OAAO;QACxB,WAAW,EAAE,MAAM,CAAC,UAAU;QAC9B,YAAY,EAAE,MAAM,CAAC,WAAW;KACjC,CAAC;IACF,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC,CAAC;IACpE,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;AAC9C,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,kBAAkB,CAAC,CAAqB;IACtD,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,qBAAqB;QAAE,OAAO,KAAK,CAAC;IACjE,MAAM,GAAG,GAAG,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,GAAG,CAAC,CAAC;IACzC,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Infrastructure co-signature over an agent's receipt (SPEC §14 — segregation of duties).
3
+ *
4
+ * Gordon's Q1: the agent that does the task cannot be the sole party reporting it.
5
+ * "Connect" — the deterministic rails that are the only door to the outside world —
6
+ * holds its own `did:key` and co-signs every receipt. A second, independent signature
7
+ * from a party the agent can't control (and, later, that holds the provider
8
+ * credentials) makes acting-without-recording structurally catchable. Reconciliation
9
+ * (`reconcile`) covers anything that still slips around the rails.
10
+ *
11
+ * This is a signed artifact carried in a normal receipt — no server or schema change.
12
+ */
13
+ export interface ReceiptCoSignature {
14
+ v: 1;
15
+ type: 'receipt_cosign';
16
+ /** The co-signer's `did:key` (Connect / the rails) — MUST differ from `agent_id`. */
17
+ cosigner_id: string;
18
+ /** Hash of the agent receipt being co-signed. */
19
+ receipt_hash: string;
20
+ /** The agent (the doer) whose receipt this is. */
21
+ agent_id: string;
22
+ cosigned_at: string;
23
+ sig: string;
24
+ }
25
+ /** Connect co-signs an agent's receipt. Only the co-signer's key can produce this. */
26
+ export declare function createCoSignature(fields: {
27
+ cosignerId: string;
28
+ receiptHash: string;
29
+ agentId: string;
30
+ cosignedAt: string;
31
+ }, cosignerPrivateKey: Uint8Array): ReceiptCoSignature;
32
+ /**
33
+ * Verify a co-signature. Requires a valid signature by `cosigner_id` AND that the
34
+ * co-signer is a **distinct** party from the acting agent (segregation of duties).
35
+ */
36
+ export declare function verifyCoSignature(c: ReceiptCoSignature): boolean;
37
+ //# sourceMappingURL=cosign.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cosign.d.ts","sourceRoot":"","sources":["../src/cosign.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB;IACjC,CAAC,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,gBAAgB,CAAC;IACvB,qFAAqF;IACrF,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,sFAAsF;AACtF,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EACxF,kBAAkB,EAAE,UAAU,GAC7B,kBAAkB,CAWpB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAYhE"}
package/dist/cosign.js ADDED
@@ -0,0 +1,38 @@
1
+ import { ed25519 } from '@noble/curves/ed25519';
2
+ import { canonicalBytes, decodeSig, encodeSig } from './encoding.js';
3
+ import { publicKeyFromDid } from './keys.js';
4
+ /** Connect co-signs an agent's receipt. Only the co-signer's key can produce this. */
5
+ export function createCoSignature(fields, cosignerPrivateKey) {
6
+ const unsigned = {
7
+ v: 1,
8
+ type: 'receipt_cosign',
9
+ cosigner_id: fields.cosignerId,
10
+ receipt_hash: fields.receiptHash,
11
+ agent_id: fields.agentId,
12
+ cosigned_at: fields.cosignedAt,
13
+ };
14
+ const sig = ed25519.sign(canonicalBytes(unsigned), cosignerPrivateKey);
15
+ return { ...unsigned, sig: encodeSig(sig) };
16
+ }
17
+ /**
18
+ * Verify a co-signature. Requires a valid signature by `cosigner_id` AND that the
19
+ * co-signer is a **distinct** party from the acting agent (segregation of duties).
20
+ */
21
+ export function verifyCoSignature(c) {
22
+ if (c?.v !== 1 || c.type !== 'receipt_cosign')
23
+ return false;
24
+ if (c.cosigner_id === c.agent_id)
25
+ return false; // doer must not co-sign itself
26
+ const pub = publicKeyFromDid(c.cosigner_id);
27
+ const sig = decodeSig(c.sig);
28
+ if (!pub || !sig)
29
+ return false;
30
+ const { sig: _omitted, ...unsigned } = c;
31
+ try {
32
+ return ed25519.verify(sig, canonicalBytes(unsigned), pub);
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ }
38
+ //# sourceMappingURL=cosign.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cosign.js","sourceRoot":"","sources":["../src/cosign.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AA2B7C,sFAAsF;AACtF,MAAM,UAAU,iBAAiB,CAC/B,MAAwF,EACxF,kBAA8B;IAE9B,MAAM,QAAQ,GAAG;QACf,CAAC,EAAE,CAAU;QACb,IAAI,EAAE,gBAAyB;QAC/B,WAAW,EAAE,MAAM,CAAC,UAAU;QAC9B,YAAY,EAAE,MAAM,CAAC,WAAW;QAChC,QAAQ,EAAE,MAAM,CAAC,OAAO;QACxB,WAAW,EAAE,MAAM,CAAC,UAAU;KAC/B,CAAC;IACF,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC,CAAC;IACvE,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,CAAqB;IACrD,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,gBAAgB;QAAE,OAAO,KAAK,CAAC;IAC5D,IAAI,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC,CAAC,+BAA+B;IAC/E,MAAM,GAAG,GAAG,gBAAgB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,GAAG,CAAC,CAAC;IACzC,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
package/dist/index.d.ts CHANGED
@@ -5,5 +5,7 @@ export { leafHash, merkleRoot, inclusionProof, verifyInclusion, consistencyProof
5
5
  export { createSTH, verifySTH, type SignedTreeHead } from './sth.js';
6
6
  export { buildA2ABody, signA2ABody, assembleA2AReceipt, a2aHash, bodyOf, verifyA2AReceipt, participantsOf, prevFor, type A2AReceipt, type A2ABody, type A2AParty, } from './a2a.js';
7
7
  export { verifyAuditBundle, type AuditBundle, type BundledReceipt, type BundledRevocation, type BundledAnchor, type BundleReport, type BundleCheck, } from './bundle.js';
8
- export { createReceipt, receiptHash, hashPayload, verifyReceipt, verifyReceiptSignature, verifyReceiptChain, type Receipt, type VerifyResult, } from './receipt.js';
8
+ export { createReceipt, receiptHash, hashPayload, saltedPayloadHash, verifyPayload, verifyReceipt, verifyReceiptSignature, verifyReceiptChain, type Receipt, type VerifyResult, } from './receipt.js';
9
+ export { createConfirmation, verifyConfirmation, type ActionConfirmation, } from './confirmation.js';
10
+ export { createCoSignature, verifyCoSignature, type ReceiptCoSignature, } from './cosign.js';
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EACL,UAAU,EACV,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,QAAQ,EACR,UAAU,EACV,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AACrE,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,MAAM,EACN,gBAAgB,EAChB,cAAc,EACd,OAAO,EACP,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,QAAQ,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,aAAa,EACb,WAAW,EACX,WAAW,EACX,aAAa,EACb,sBAAsB,EACtB,kBAAkB,EAClB,KAAK,OAAO,EACZ,KAAK,YAAY,GAClB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EACL,UAAU,EACV,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,QAAQ,EACR,UAAU,EACV,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AACrE,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,MAAM,EACN,gBAAgB,EAChB,cAAc,EACd,OAAO,EACP,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,QAAQ,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,sBAAsB,EACtB,kBAAkB,EAClB,KAAK,OAAO,EACZ,KAAK,YAAY,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,kBAAkB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -5,5 +5,7 @@ export { leafHash, merkleRoot, inclusionProof, verifyInclusion, consistencyProof
5
5
  export { createSTH, verifySTH } from './sth.js';
6
6
  export { buildA2ABody, signA2ABody, assembleA2AReceipt, a2aHash, bodyOf, verifyA2AReceipt, participantsOf, prevFor, } from './a2a.js';
7
7
  export { verifyAuditBundle, } from './bundle.js';
8
- export { createReceipt, receiptHash, hashPayload, verifyReceipt, verifyReceiptSignature, verifyReceiptChain, } from './receipt.js';
8
+ export { createReceipt, receiptHash, hashPayload, saltedPayloadHash, verifyPayload, verifyReceipt, verifyReceiptSignature, verifyReceiptChain, } from './receipt.js';
9
+ export { createConfirmation, verifyConfirmation, } from './confirmation.js';
10
+ export { createCoSignature, verifyCoSignature, } from './cosign.js';
9
11
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAgB,MAAM,WAAW,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EACL,UAAU,EACV,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,WAAW,GAIZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,QAAQ,EACR,UAAU,EACV,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAuB,MAAM,UAAU,CAAC;AACrE,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,MAAM,EACN,gBAAgB,EAChB,cAAc,EACd,OAAO,GAIR,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,iBAAiB,GAOlB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,aAAa,EACb,WAAW,EACX,WAAW,EACX,aAAa,EACb,sBAAsB,EACtB,kBAAkB,GAGnB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAgB,MAAM,WAAW,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EACL,UAAU,EACV,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,WAAW,GAIZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,QAAQ,EACR,UAAU,EACV,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAuB,MAAM,UAAU,CAAC;AACrE,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,MAAM,EACN,gBAAgB,EAChB,cAAc,EACd,OAAO,GAIR,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,iBAAiB,GAOlB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,sBAAsB,EACtB,kBAAkB,GAGnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GAEnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,iBAAiB,EACjB,iBAAiB,GAElB,MAAM,aAAa,CAAC"}
package/dist/receipt.d.ts CHANGED
@@ -8,6 +8,11 @@ export interface Receipt {
8
8
  payload_hash: string;
9
9
  ts: string;
10
10
  prev: string | null;
11
+ /** Optional provenance (SPEC §3). Present when set; covered by the signature. */
12
+ runtime_hash?: string;
13
+ model_id?: string;
14
+ /** Hash of the product's tool/scope manifest that governed this action. */
15
+ manifest_hash?: string;
11
16
  sig: string;
12
17
  }
13
18
  export interface VerifyResult {
@@ -15,6 +20,20 @@ export interface VerifyResult {
15
20
  error?: string;
16
21
  }
17
22
  export declare function hashPayload(payload: Uint8Array | string): string;
23
+ /**
24
+ * Privacy-preserving payload commitment: `sha256(nonce ‖ payload)`. A bare
25
+ * `hashPayload` of a low-entropy payload ("phone X, amount 500") is dictionary-
26
+ * attackable from the public anchored log, and a linkable hash can itself be
27
+ * personal data (PDPL). The per-receipt `nonce` is kept operator-side (NOT in the
28
+ * receipt), so the on-chain value reveals nothing; keep it to later prove the
29
+ * payload with `verifyPayload`. If `nonce` is omitted a fresh 16-byte one is drawn.
30
+ */
31
+ export declare function saltedPayloadHash(payload: Uint8Array | string, nonce?: string): {
32
+ payload_hash: string;
33
+ nonce: string;
34
+ };
35
+ /** Prove a payload matches a salted `payload_hash`, given the nonce kept at record time. */
36
+ export declare function verifyPayload(payload: Uint8Array | string, nonce: string, payloadHash: string): boolean;
18
37
  export declare function createReceipt(fields: {
19
38
  agentId: string;
20
39
  delegation: DelegationCert[];
@@ -23,6 +42,10 @@ export declare function createReceipt(fields: {
23
42
  payloadHash: string;
24
43
  ts: string;
25
44
  prev: string | null;
45
+ /** Optional provenance — included in the signed receipt only when provided. */
46
+ runtimeHash?: string;
47
+ modelId?: string;
48
+ manifestHash?: string;
26
49
  }, agentPrivateKey: Uint8Array): Receipt;
27
50
  /** Hash of the full receipt (incl. sig) — what the next receipt's `prev` points to. */
28
51
  export declare function receiptHash(receipt: Receipt): string;
@@ -1 +1 @@
1
- {"version":3,"file":"receipt.d.ts","sourceRoot":"","sources":["../src/receipt.ts"],"names":[],"mappings":"AAKA,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEhF,MAAM,WAAW,OAAO;IACtB,CAAC,EAAE,CAAC,CAAC;IACL,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,CAGhE;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE;IACN,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,EACD,eAAe,EAAE,UAAU,GAC1B,OAAO,CAcT;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAEpD;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAUhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,IAAI,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,GACzF,YAAY,CAwBd;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,OAAO,EAAE,EACnB,IAAI,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAO,GAC3D,YAAY,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CASzC"}
1
+ {"version":3,"file":"receipt.d.ts","sourceRoot":"","sources":["../src/receipt.ts"],"names":[],"mappings":"AAKA,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEhF,MAAM,WAAW,OAAO;IACtB,CAAC,EAAE,CAAC,CAAC;IACL,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,CAGhE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,UAAU,GAAG,MAAM,EAC5B,KAAK,CAAC,EAAE,MAAM,GACb;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAQzC;AAED,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAMvG;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE;IACN,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,EACD,eAAe,EAAE,UAAU,GAC1B,OAAO,CAiBT;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAEpD;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAUhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,IAAI,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,GACzF,YAAY,CAwBd;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,OAAO,EAAE,EACnB,IAAI,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAO,GAC3D,YAAY,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CASzC"}
package/dist/receipt.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ed25519 } from '@noble/curves/ed25519';
2
2
  import { sha256 } from '@noble/hashes/sha256';
3
- import { bytesToHex } from '@noble/hashes/utils';
3
+ import { bytesToHex, hexToBytes, randomBytes } from '@noble/hashes/utils';
4
4
  import { canonicalBytes, decodeSig, encodeSig, jcsHash } from './encoding.js';
5
5
  import { publicKeyFromDid } from './keys.js';
6
6
  import { scopesAllow, verifyChain } from './delegation.js';
@@ -8,6 +8,32 @@ export function hashPayload(payload) {
8
8
  const bytes = typeof payload === 'string' ? new TextEncoder().encode(payload) : payload;
9
9
  return `sha256:${bytesToHex(sha256(bytes))}`;
10
10
  }
11
+ /**
12
+ * Privacy-preserving payload commitment: `sha256(nonce ‖ payload)`. A bare
13
+ * `hashPayload` of a low-entropy payload ("phone X, amount 500") is dictionary-
14
+ * attackable from the public anchored log, and a linkable hash can itself be
15
+ * personal data (PDPL). The per-receipt `nonce` is kept operator-side (NOT in the
16
+ * receipt), so the on-chain value reveals nothing; keep it to later prove the
17
+ * payload with `verifyPayload`. If `nonce` is omitted a fresh 16-byte one is drawn.
18
+ */
19
+ export function saltedPayloadHash(payload, nonce) {
20
+ const nonceHex = nonce ?? bytesToHex(randomBytes(16));
21
+ const nonceBytes = hexToBytes(nonceHex);
22
+ const payloadBytes = typeof payload === 'string' ? new TextEncoder().encode(payload) : payload;
23
+ const combined = new Uint8Array(nonceBytes.length + payloadBytes.length);
24
+ combined.set(nonceBytes, 0);
25
+ combined.set(payloadBytes, nonceBytes.length);
26
+ return { payload_hash: `sha256:${bytesToHex(sha256(combined))}`, nonce: nonceHex };
27
+ }
28
+ /** Prove a payload matches a salted `payload_hash`, given the nonce kept at record time. */
29
+ export function verifyPayload(payload, nonce, payloadHash) {
30
+ try {
31
+ return saltedPayloadHash(payload, nonce).payload_hash === payloadHash;
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
11
37
  export function createReceipt(fields, agentPrivateKey) {
12
38
  if (Number.isNaN(Date.parse(fields.ts)))
13
39
  throw new Error(`invalid ts timestamp: ${fields.ts}`);
@@ -20,6 +46,9 @@ export function createReceipt(fields, agentPrivateKey) {
20
46
  payload_hash: fields.payloadHash,
21
47
  ts: fields.ts,
22
48
  prev: fields.prev,
49
+ ...(fields.runtimeHash ? { runtime_hash: fields.runtimeHash } : {}),
50
+ ...(fields.modelId ? { model_id: fields.modelId } : {}),
51
+ ...(fields.manifestHash ? { manifest_hash: fields.manifestHash } : {}),
23
52
  };
24
53
  const sig = ed25519.sign(canonicalBytes(unsigned), agentPrivateKey);
25
54
  return { ...unsigned, sig: encodeSig(sig) };
@@ -1 +1 @@
1
- {"version":3,"file":"receipt.js","sourceRoot":"","sources":["../src/receipt.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"receipt.js","sourceRoot":"","sources":["../src/receipt.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zanii/core",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Zanii protocol: verifiable identity, signed action receipts, Merkle transparency-log proofs. Pure, no I/O.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://ledger.zanii.agency",
@@ -0,0 +1,53 @@
1
+ import { ed25519 } from '@noble/curves/ed25519';
2
+ import { canonicalBytes, decodeSig, encodeSig } from './encoding.js';
3
+ import { publicKeyFromDid } from './keys.js';
4
+
5
+ /**
6
+ * Owner confirmation of an irreversible action (SPEC §13 / Article VI).
7
+ *
8
+ * The human owner signs the exact action hash with their `did:key`. This is the
9
+ * cryptographic evidence a person confirmed — replacing an in-memory "yes" that
10
+ * proves nothing. Recorded as its own `action_confirmation` receipt so a dispute
11
+ * ("did the client actually approve this payment?") has a verifiable answer.
12
+ */
13
+ export interface ActionConfirmation {
14
+ v: 1;
15
+ type: 'action_confirmation';
16
+ /** The owner's `did:key`. */
17
+ owner_id: string;
18
+ /** `sha256:…` hash of the exact action `{tool, args}` being confirmed. */
19
+ action_hash: string;
20
+ confirmed_at: string;
21
+ /** Ed25519 by the owner over JCS of the confirmation without `sig`. */
22
+ sig: string;
23
+ }
24
+
25
+ /** Owner signs an action hash. Only the owner's key can produce this. */
26
+ export function createConfirmation(
27
+ fields: { ownerId: string; actionHash: string; confirmedAt: string },
28
+ ownerPrivateKey: Uint8Array,
29
+ ): ActionConfirmation {
30
+ const unsigned = {
31
+ v: 1 as const,
32
+ type: 'action_confirmation' as const,
33
+ owner_id: fields.ownerId,
34
+ action_hash: fields.actionHash,
35
+ confirmed_at: fields.confirmedAt,
36
+ };
37
+ const sig = ed25519.sign(canonicalBytes(unsigned), ownerPrivateKey);
38
+ return { ...unsigned, sig: encodeSig(sig) };
39
+ }
40
+
41
+ /** Verify a confirmation's signature against the owner DID it names. */
42
+ export function verifyConfirmation(c: ActionConfirmation): boolean {
43
+ if (c?.v !== 1 || c.type !== 'action_confirmation') return false;
44
+ const pub = publicKeyFromDid(c.owner_id);
45
+ const sig = decodeSig(c.sig);
46
+ if (!pub || !sig) return false;
47
+ const { sig: _omitted, ...unsigned } = c;
48
+ try {
49
+ return ed25519.verify(sig, canonicalBytes(unsigned), pub);
50
+ } catch {
51
+ return false;
52
+ }
53
+ }
package/src/cosign.ts ADDED
@@ -0,0 +1,63 @@
1
+ import { ed25519 } from '@noble/curves/ed25519';
2
+ import { canonicalBytes, decodeSig, encodeSig } from './encoding.js';
3
+ import { publicKeyFromDid } from './keys.js';
4
+
5
+ /**
6
+ * Infrastructure co-signature over an agent's receipt (SPEC §14 — segregation of duties).
7
+ *
8
+ * Gordon's Q1: the agent that does the task cannot be the sole party reporting it.
9
+ * "Connect" — the deterministic rails that are the only door to the outside world —
10
+ * holds its own `did:key` and co-signs every receipt. A second, independent signature
11
+ * from a party the agent can't control (and, later, that holds the provider
12
+ * credentials) makes acting-without-recording structurally catchable. Reconciliation
13
+ * (`reconcile`) covers anything that still slips around the rails.
14
+ *
15
+ * This is a signed artifact carried in a normal receipt — no server or schema change.
16
+ */
17
+ export interface ReceiptCoSignature {
18
+ v: 1;
19
+ type: 'receipt_cosign';
20
+ /** The co-signer's `did:key` (Connect / the rails) — MUST differ from `agent_id`. */
21
+ cosigner_id: string;
22
+ /** Hash of the agent receipt being co-signed. */
23
+ receipt_hash: string;
24
+ /** The agent (the doer) whose receipt this is. */
25
+ agent_id: string;
26
+ cosigned_at: string;
27
+ sig: string;
28
+ }
29
+
30
+ /** Connect co-signs an agent's receipt. Only the co-signer's key can produce this. */
31
+ export function createCoSignature(
32
+ fields: { cosignerId: string; receiptHash: string; agentId: string; cosignedAt: string },
33
+ cosignerPrivateKey: Uint8Array,
34
+ ): ReceiptCoSignature {
35
+ const unsigned = {
36
+ v: 1 as const,
37
+ type: 'receipt_cosign' as const,
38
+ cosigner_id: fields.cosignerId,
39
+ receipt_hash: fields.receiptHash,
40
+ agent_id: fields.agentId,
41
+ cosigned_at: fields.cosignedAt,
42
+ };
43
+ const sig = ed25519.sign(canonicalBytes(unsigned), cosignerPrivateKey);
44
+ return { ...unsigned, sig: encodeSig(sig) };
45
+ }
46
+
47
+ /**
48
+ * Verify a co-signature. Requires a valid signature by `cosigner_id` AND that the
49
+ * co-signer is a **distinct** party from the acting agent (segregation of duties).
50
+ */
51
+ export function verifyCoSignature(c: ReceiptCoSignature): boolean {
52
+ if (c?.v !== 1 || c.type !== 'receipt_cosign') return false;
53
+ if (c.cosigner_id === c.agent_id) return false; // doer must not co-sign itself
54
+ const pub = publicKeyFromDid(c.cosigner_id);
55
+ const sig = decodeSig(c.sig);
56
+ if (!pub || !sig) return false;
57
+ const { sig: _omitted, ...unsigned } = c;
58
+ try {
59
+ return ed25519.verify(sig, canonicalBytes(unsigned), pub);
60
+ } catch {
61
+ return false;
62
+ }
63
+ }
package/src/index.ts CHANGED
@@ -48,9 +48,21 @@ export {
48
48
  createReceipt,
49
49
  receiptHash,
50
50
  hashPayload,
51
+ saltedPayloadHash,
52
+ verifyPayload,
51
53
  verifyReceipt,
52
54
  verifyReceiptSignature,
53
55
  verifyReceiptChain,
54
56
  type Receipt,
55
57
  type VerifyResult,
56
58
  } from './receipt.js';
59
+ export {
60
+ createConfirmation,
61
+ verifyConfirmation,
62
+ type ActionConfirmation,
63
+ } from './confirmation.js';
64
+ export {
65
+ createCoSignature,
66
+ verifyCoSignature,
67
+ type ReceiptCoSignature,
68
+ } from './cosign.js';
package/src/receipt.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ed25519 } from '@noble/curves/ed25519';
2
2
  import { sha256 } from '@noble/hashes/sha256';
3
- import { bytesToHex } from '@noble/hashes/utils';
3
+ import { bytesToHex, hexToBytes, randomBytes } from '@noble/hashes/utils';
4
4
  import { canonicalBytes, decodeSig, encodeSig, jcsHash } from './encoding.js';
5
5
  import { publicKeyFromDid } from './keys.js';
6
6
  import { scopesAllow, verifyChain, type DelegationCert } from './delegation.js';
@@ -14,6 +14,11 @@ export interface Receipt {
14
14
  payload_hash: string;
15
15
  ts: string;
16
16
  prev: string | null;
17
+ /** Optional provenance (SPEC §3). Present when set; covered by the signature. */
18
+ runtime_hash?: string;
19
+ model_id?: string;
20
+ /** Hash of the product's tool/scope manifest that governed this action. */
21
+ manifest_hash?: string;
17
22
  sig: string;
18
23
  }
19
24
 
@@ -27,6 +32,36 @@ export function hashPayload(payload: Uint8Array | string): string {
27
32
  return `sha256:${bytesToHex(sha256(bytes))}`;
28
33
  }
29
34
 
35
+ /**
36
+ * Privacy-preserving payload commitment: `sha256(nonce ‖ payload)`. A bare
37
+ * `hashPayload` of a low-entropy payload ("phone X, amount 500") is dictionary-
38
+ * attackable from the public anchored log, and a linkable hash can itself be
39
+ * personal data (PDPL). The per-receipt `nonce` is kept operator-side (NOT in the
40
+ * receipt), so the on-chain value reveals nothing; keep it to later prove the
41
+ * payload with `verifyPayload`. If `nonce` is omitted a fresh 16-byte one is drawn.
42
+ */
43
+ export function saltedPayloadHash(
44
+ payload: Uint8Array | string,
45
+ nonce?: string,
46
+ ): { payload_hash: string; nonce: string } {
47
+ const nonceHex = nonce ?? bytesToHex(randomBytes(16));
48
+ const nonceBytes = hexToBytes(nonceHex);
49
+ const payloadBytes = typeof payload === 'string' ? new TextEncoder().encode(payload) : payload;
50
+ const combined = new Uint8Array(nonceBytes.length + payloadBytes.length);
51
+ combined.set(nonceBytes, 0);
52
+ combined.set(payloadBytes, nonceBytes.length);
53
+ return { payload_hash: `sha256:${bytesToHex(sha256(combined))}`, nonce: nonceHex };
54
+ }
55
+
56
+ /** Prove a payload matches a salted `payload_hash`, given the nonce kept at record time. */
57
+ export function verifyPayload(payload: Uint8Array | string, nonce: string, payloadHash: string): boolean {
58
+ try {
59
+ return saltedPayloadHash(payload, nonce).payload_hash === payloadHash;
60
+ } catch {
61
+ return false;
62
+ }
63
+ }
64
+
30
65
  export function createReceipt(
31
66
  fields: {
32
67
  agentId: string;
@@ -36,6 +71,10 @@ export function createReceipt(
36
71
  payloadHash: string;
37
72
  ts: string;
38
73
  prev: string | null;
74
+ /** Optional provenance — included in the signed receipt only when provided. */
75
+ runtimeHash?: string;
76
+ modelId?: string;
77
+ manifestHash?: string;
39
78
  },
40
79
  agentPrivateKey: Uint8Array,
41
80
  ): Receipt {
@@ -49,6 +88,9 @@ export function createReceipt(
49
88
  payload_hash: fields.payloadHash,
50
89
  ts: fields.ts,
51
90
  prev: fields.prev,
91
+ ...(fields.runtimeHash ? { runtime_hash: fields.runtimeHash } : {}),
92
+ ...(fields.modelId ? { model_id: fields.modelId } : {}),
93
+ ...(fields.manifestHash ? { manifest_hash: fields.manifestHash } : {}),
52
94
  };
53
95
  const sig = ed25519.sign(canonicalBytes(unsigned), agentPrivateKey);
54
96
  return { ...unsigned, sig: encodeSig(sig) };