@zanii/core 0.1.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/LICENSE +159 -0
- package/README.md +64 -0
- package/dist/a2a.d.ts +58 -0
- package/dist/a2a.d.ts.map +1 -0
- package/dist/a2a.js +102 -0
- package/dist/a2a.js.map +1 -0
- package/dist/bundle.d.ts +55 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/bundle.js +92 -0
- package/dist/bundle.js.map +1 -0
- package/dist/delegation.d.ts +48 -0
- package/dist/delegation.d.ts.map +1 -0
- package/dist/delegation.js +110 -0
- package/dist/delegation.js.map +1 -0
- package/dist/encoding.d.ts +8 -0
- package/dist/encoding.d.ts.map +1 -0
- package/dist/encoding.js +29 -0
- package/dist/encoding.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/keys.d.ts +10 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +33 -0
- package/dist/keys.js.map +1 -0
- package/dist/merkle.d.ts +12 -0
- package/dist/merkle.d.ts.map +1 -0
- package/dist/merkle.js +146 -0
- package/dist/merkle.js.map +1 -0
- package/dist/receipt.d.ts +49 -0
- package/dist/receipt.d.ts.map +1 -0
- package/dist/receipt.js +87 -0
- package/dist/receipt.js.map +1 -0
- package/dist/sth.d.ts +17 -0
- package/dist/sth.d.ts.map +1 -0
- package/dist/sth.js +24 -0
- package/dist/sth.js.map +1 -0
- package/package.json +43 -0
- package/src/a2a.ts +139 -0
- package/src/bundle.ts +176 -0
- package/src/delegation.ts +134 -0
- package/src/encoding.ts +30 -0
- package/src/index.ts +56 -0
- package/src/keys.ts +38 -0
- package/src/merkle.ts +154 -0
- package/src/receipt.ts +123 -0
- package/src/sth.ts +35 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { ed25519 } from '@noble/curves/ed25519';
|
|
2
|
+
import { canonicalBytes, decodeSig, encodeSig, jcsHash } from './encoding.js';
|
|
3
|
+
import { publicKeyFromDid } from './keys.js';
|
|
4
|
+
export function createCert(fields, issuerPrivateKey) {
|
|
5
|
+
if (fields.scopes.length === 0)
|
|
6
|
+
throw new Error('cert must grant at least one scope');
|
|
7
|
+
if (Number.isNaN(Date.parse(fields.exp)))
|
|
8
|
+
throw new Error(`invalid exp timestamp: ${fields.exp}`);
|
|
9
|
+
const unsigned = { v: 1, ...fields };
|
|
10
|
+
const sig = ed25519.sign(canonicalBytes(unsigned), issuerPrivateKey);
|
|
11
|
+
return { ...unsigned, sig: encodeSig(sig) };
|
|
12
|
+
}
|
|
13
|
+
/** Hash of the full cert (incl. sig) — the revocation identifier. */
|
|
14
|
+
export function certHash(cert) {
|
|
15
|
+
return jcsHash(cert);
|
|
16
|
+
}
|
|
17
|
+
/** Does `scope` cover `target`? `a.*` covers `a`, `a.b`, `a.b.c`, `a.*`; `*` covers all. */
|
|
18
|
+
export function scopeCovers(scope, target) {
|
|
19
|
+
if (scope === '*')
|
|
20
|
+
return true;
|
|
21
|
+
if (scope === target)
|
|
22
|
+
return true;
|
|
23
|
+
if (scope.endsWith('.*')) {
|
|
24
|
+
const prefix = scope.slice(0, -2);
|
|
25
|
+
return target === prefix || target.startsWith(prefix + '.');
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
export function scopesAllow(scopes, target) {
|
|
30
|
+
return scopes.some((s) => scopeCovers(s, target));
|
|
31
|
+
}
|
|
32
|
+
export function createRevocation(cert, ts, issuerPrivateKey) {
|
|
33
|
+
if (Number.isNaN(Date.parse(ts)))
|
|
34
|
+
throw new Error(`invalid ts timestamp: ${ts}`);
|
|
35
|
+
const unsigned = { v: 1, type: 'revocation', cert, ts };
|
|
36
|
+
const sig = ed25519.sign(canonicalBytes(unsigned), issuerPrivateKey);
|
|
37
|
+
return { ...unsigned, sig: encodeSig(sig) };
|
|
38
|
+
}
|
|
39
|
+
/** Valid iff the embedded cert verifies AND the record is signed by the cert's issuer. */
|
|
40
|
+
export function verifyRevocation(record) {
|
|
41
|
+
if (record.v !== 1 || record.type !== 'revocation')
|
|
42
|
+
return false;
|
|
43
|
+
if (!record.cert || !verifyCertSignature(record.cert))
|
|
44
|
+
return false;
|
|
45
|
+
const pub = publicKeyFromDid(record.cert.issuer);
|
|
46
|
+
const sig = decodeSig(record.sig);
|
|
47
|
+
if (!pub || !sig)
|
|
48
|
+
return false;
|
|
49
|
+
const { sig: _omitted, ...unsigned } = record;
|
|
50
|
+
try {
|
|
51
|
+
return ed25519.verify(sig, canonicalBytes(unsigned), pub);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function verifyCertSignature(cert) {
|
|
58
|
+
const pub = publicKeyFromDid(cert.issuer);
|
|
59
|
+
const sig = decodeSig(cert.sig);
|
|
60
|
+
if (!pub || !sig)
|
|
61
|
+
return false;
|
|
62
|
+
const { sig: _omitted, ...unsigned } = cert;
|
|
63
|
+
try {
|
|
64
|
+
return ed25519.verify(sig, canonicalBytes(unsigned), pub);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Validate a delegation chain (root first) per SPEC §2.
|
|
72
|
+
* `at` defaults to now; `revoked` is a set of cert hashes.
|
|
73
|
+
*/
|
|
74
|
+
export function verifyChain(chain, opts) {
|
|
75
|
+
if (!Array.isArray(chain) || chain.length === 0)
|
|
76
|
+
return { ok: false, error: 'empty delegation chain' };
|
|
77
|
+
const at = opts.at ?? new Date();
|
|
78
|
+
const root = chain[0];
|
|
79
|
+
if (opts.expectedRoot && root.issuer !== opts.expectedRoot) {
|
|
80
|
+
return { ok: false, error: `root issuer ${root.issuer} is not expected owner ${opts.expectedRoot}` };
|
|
81
|
+
}
|
|
82
|
+
if (chain[chain.length - 1].subject !== opts.agentId) {
|
|
83
|
+
return { ok: false, error: 'chain does not terminate at the agent' };
|
|
84
|
+
}
|
|
85
|
+
// Fold scopes down the chain: a delegate can only narrow, never widen.
|
|
86
|
+
// ponytail: widening scopes are silently dropped, not rejected — reject-on-widen when policy UX exists (Phase 2)
|
|
87
|
+
let effectiveScopes = [];
|
|
88
|
+
for (let i = 0; i < chain.length; i++) {
|
|
89
|
+
const cert = chain[i];
|
|
90
|
+
if (cert.v !== 1)
|
|
91
|
+
return { ok: false, error: `cert ${i}: unsupported version` };
|
|
92
|
+
if (i > 0 && cert.issuer !== chain[i - 1].subject) {
|
|
93
|
+
return { ok: false, error: `cert ${i}: issuer does not match previous subject` };
|
|
94
|
+
}
|
|
95
|
+
const exp = Date.parse(cert.exp);
|
|
96
|
+
if (Number.isNaN(exp))
|
|
97
|
+
return { ok: false, error: `cert ${i}: invalid exp` };
|
|
98
|
+
if (at.getTime() >= exp)
|
|
99
|
+
return { ok: false, error: `cert ${i}: expired` };
|
|
100
|
+
if (opts.revoked?.has(certHash(cert)))
|
|
101
|
+
return { ok: false, error: `cert ${i}: revoked` };
|
|
102
|
+
if (!verifyCertSignature(cert))
|
|
103
|
+
return { ok: false, error: `cert ${i}: bad signature` };
|
|
104
|
+
effectiveScopes = i === 0 ? [...cert.scopes] : cert.scopes.filter((s) => scopesAllow(effectiveScopes, s));
|
|
105
|
+
}
|
|
106
|
+
if (effectiveScopes.length === 0)
|
|
107
|
+
return { ok: false, error: 'chain grants no effective scopes' };
|
|
108
|
+
return { ok: true, effectiveScopes };
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=delegation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation.js","sourceRoot":"","sources":["../src/delegation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** RFC 8785 canonical JSON, UTF-8 bytes. Throws on non-serializable input. */
|
|
2
|
+
export declare function canonicalBytes(obj: unknown): Uint8Array;
|
|
3
|
+
/** `sha256:<hex>` of the JCS form of obj. */
|
|
4
|
+
export declare function jcsHash(obj: unknown): string;
|
|
5
|
+
export declare function encodeSig(sig: Uint8Array): string;
|
|
6
|
+
/** Returns null instead of throwing: verification paths must not crash on malformed input. */
|
|
7
|
+
export declare function decodeSig(s: string): Uint8Array | null;
|
|
8
|
+
//# sourceMappingURL=encoding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../src/encoding.ts"],"names":[],"mappings":"AAOA,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CAIvD;AAED,6CAA6C;AAC7C,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAE5C;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAEjD;AAED,8FAA8F;AAC9F,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAKtD"}
|
package/dist/encoding.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
2
|
+
import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
|
|
3
|
+
import canonicalizeImport from 'canonicalize';
|
|
4
|
+
// canonicalize is CJS (`module.exports = fn`) with a .d.ts that hides the call signature
|
|
5
|
+
const canonicalizeJson = canonicalizeImport;
|
|
6
|
+
/** RFC 8785 canonical JSON, UTF-8 bytes. Throws on non-serializable input. */
|
|
7
|
+
export function canonicalBytes(obj) {
|
|
8
|
+
const s = canonicalizeJson(obj);
|
|
9
|
+
if (typeof s !== 'string')
|
|
10
|
+
throw new Error('value is not canonicalizable JSON');
|
|
11
|
+
return new TextEncoder().encode(s);
|
|
12
|
+
}
|
|
13
|
+
/** `sha256:<hex>` of the JCS form of obj. */
|
|
14
|
+
export function jcsHash(obj) {
|
|
15
|
+
return `sha256:${bytesToHex(sha256(canonicalBytes(obj)))}`;
|
|
16
|
+
}
|
|
17
|
+
export function encodeSig(sig) {
|
|
18
|
+
return `ed25519:${bytesToHex(sig)}`;
|
|
19
|
+
}
|
|
20
|
+
/** Returns null instead of throwing: verification paths must not crash on malformed input. */
|
|
21
|
+
export function decodeSig(s) {
|
|
22
|
+
if (typeof s !== 'string' || !s.startsWith('ed25519:'))
|
|
23
|
+
return null;
|
|
24
|
+
const hex = s.slice('ed25519:'.length);
|
|
25
|
+
if (!/^[0-9a-f]{128}$/.test(hex))
|
|
26
|
+
return null;
|
|
27
|
+
return hexToBytes(hex);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=encoding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoding.js","sourceRoot":"","sources":["../src/encoding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,kBAAkB,MAAM,cAAc,CAAC;AAE9C,yFAAyF;AACzF,MAAM,gBAAgB,GAAG,kBAAmE,CAAC;AAE7F,8EAA8E;AAC9E,MAAM,UAAU,cAAc,CAAC,GAAY;IACzC,MAAM,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAChF,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,OAAO,CAAC,GAAY;IAClC,OAAO,UAAU,UAAU,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAe;IACvC,OAAO,WAAW,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;AACtC,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,SAAS,CAAC,CAAS;IACjC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IACpE,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { generateKeypair, didFromPublicKey, publicKeyFromDid, type Keypair } from './keys.js';
|
|
2
|
+
export { canonicalBytes, jcsHash } from './encoding.js';
|
|
3
|
+
export { createCert, certHash, createRevocation, verifyRevocation, verifyCertSignature, verifyChain, scopeCovers, scopesAllow, type DelegationCert, type RevocationRecord, type ChainResult, } from './delegation.js';
|
|
4
|
+
export { leafHash, merkleRoot, inclusionProof, verifyInclusion, consistencyProof, verifyConsistency, } from './merkle.js';
|
|
5
|
+
export { createSTH, verifySTH, type SignedTreeHead } from './sth.js';
|
|
6
|
+
export { buildA2ABody, signA2ABody, assembleA2AReceipt, a2aHash, bodyOf, verifyA2AReceipt, participantsOf, prevFor, type A2AReceipt, type A2ABody, type A2AParty, } from './a2a.js';
|
|
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';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { generateKeypair, didFromPublicKey, publicKeyFromDid } from './keys.js';
|
|
2
|
+
export { canonicalBytes, jcsHash } from './encoding.js';
|
|
3
|
+
export { createCert, certHash, createRevocation, verifyRevocation, verifyCertSignature, verifyChain, scopeCovers, scopesAllow, } from './delegation.js';
|
|
4
|
+
export { leafHash, merkleRoot, inclusionProof, verifyInclusion, consistencyProof, verifyConsistency, } from './merkle.js';
|
|
5
|
+
export { createSTH, verifySTH } from './sth.js';
|
|
6
|
+
export { buildA2ABody, signA2ABody, assembleA2AReceipt, a2aHash, bodyOf, verifyA2AReceipt, participantsOf, prevFor, } from './a2a.js';
|
|
7
|
+
export { verifyAuditBundle, } from './bundle.js';
|
|
8
|
+
export { createReceipt, receiptHash, hashPayload, verifyReceipt, verifyReceiptSignature, verifyReceiptChain, } from './receipt.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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"}
|
package/dist/keys.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface Keypair {
|
|
2
|
+
privateKey: Uint8Array;
|
|
3
|
+
publicKey: Uint8Array;
|
|
4
|
+
did: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function generateKeypair(): Keypair;
|
|
7
|
+
export declare function didFromPublicKey(publicKey: Uint8Array): string;
|
|
8
|
+
/** Returns null instead of throwing: verification paths must not crash on malformed input. */
|
|
9
|
+
export declare function publicKeyFromDid(did: string): Uint8Array | null;
|
|
10
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,UAAU,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,eAAe,IAAI,OAAO,CAIzC;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAM9D;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAU/D"}
|
package/dist/keys.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ed25519 } from '@noble/curves/ed25519';
|
|
2
|
+
import { base58 } from '@scure/base';
|
|
3
|
+
const ED25519_MULTICODEC = Uint8Array.from([0xed, 0x01]);
|
|
4
|
+
const DID_PREFIX = 'did:key:z';
|
|
5
|
+
export function generateKeypair() {
|
|
6
|
+
const privateKey = ed25519.utils.randomPrivateKey();
|
|
7
|
+
const publicKey = ed25519.getPublicKey(privateKey);
|
|
8
|
+
return { privateKey, publicKey, did: didFromPublicKey(publicKey) };
|
|
9
|
+
}
|
|
10
|
+
export function didFromPublicKey(publicKey) {
|
|
11
|
+
if (publicKey.length !== 32)
|
|
12
|
+
throw new Error('ed25519 public key must be 32 bytes');
|
|
13
|
+
const prefixed = new Uint8Array(2 + 32);
|
|
14
|
+
prefixed.set(ED25519_MULTICODEC);
|
|
15
|
+
prefixed.set(publicKey, 2);
|
|
16
|
+
return DID_PREFIX + base58.encode(prefixed);
|
|
17
|
+
}
|
|
18
|
+
/** Returns null instead of throwing: verification paths must not crash on malformed input. */
|
|
19
|
+
export function publicKeyFromDid(did) {
|
|
20
|
+
if (typeof did !== 'string' || !did.startsWith(DID_PREFIX))
|
|
21
|
+
return null;
|
|
22
|
+
let decoded;
|
|
23
|
+
try {
|
|
24
|
+
decoded = base58.decode(did.slice(DID_PREFIX.length));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
if (decoded.length !== 34 || decoded[0] !== 0xed || decoded[1] !== 0x01)
|
|
30
|
+
return null;
|
|
31
|
+
return decoded.slice(2);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=keys.js.map
|
package/dist/keys.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,kBAAkB,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AACzD,MAAM,UAAU,GAAG,WAAW,CAAC;AAQ/B,MAAM,UAAU,eAAe;IAC7B,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;IACpD,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;IACnD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,EAAE,gBAAgB,CAAC,SAAS,CAAC,EAAE,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAqB;IACpD,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACpF,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACxC,QAAQ,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACjC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAC3B,OAAO,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IACxE,IAAI,OAAmB,CAAC;IACxB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,EAAE,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACrF,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC"}
|
package/dist/merkle.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** SHA-256(0x00 || data) */
|
|
2
|
+
export declare function leafHash(data: Uint8Array): Uint8Array;
|
|
3
|
+
export declare function merkleRoot(leafHashes: Uint8Array[]): Uint8Array;
|
|
4
|
+
/** Audit path for leaf `index` in a tree of the given leaf hashes (RFC 6962 §2.1.1). */
|
|
5
|
+
export declare function inclusionProof(index: number, leafHashes: Uint8Array[]): Uint8Array[];
|
|
6
|
+
/** RFC 9162 §2.1.3.2. Pure; returns false on any malformed input. */
|
|
7
|
+
export declare function verifyInclusion(leaf: Uint8Array, index: number, size: number, proof: Uint8Array[], root: Uint8Array): boolean;
|
|
8
|
+
/** Consistency proof from tree size m to the current tree (RFC 6962 §2.1.2). */
|
|
9
|
+
export declare function consistencyProof(m: number, leafHashes: Uint8Array[]): Uint8Array[];
|
|
10
|
+
/** RFC 9162 §2.1.4.2. Pure; returns false on any malformed input. */
|
|
11
|
+
export declare function verifyConsistency(size1: number, size2: number, root1: Uint8Array, root2: Uint8Array, proof: Uint8Array[]): boolean;
|
|
12
|
+
//# sourceMappingURL=merkle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merkle.d.ts","sourceRoot":"","sources":["../src/merkle.ts"],"names":[],"mappings":"AASA,4BAA4B;AAC5B,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAKrD;AAmBD,wBAAgB,UAAU,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,UAAU,CAM/D;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAUpF;AAID,qEAAqE;AACrE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,UAAU,EAAE,EACnB,IAAI,EAAE,UAAU,GACf,OAAO,CAuBT;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAOlF;AAWD,qEAAqE;AACrE,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,UAAU,EAAE,GAClB,OAAO,CAsCT"}
|
package/dist/merkle.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 6962 / RFC 9162 Merkle tree: root, inclusion proofs, consistency proofs.
|
|
3
|
+
* All functions operate on arrays of *leaf hashes* (already 0x00-prefixed-hashed).
|
|
4
|
+
*/
|
|
5
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
6
|
+
const LEAF_PREFIX = 0x00;
|
|
7
|
+
const NODE_PREFIX = 0x01;
|
|
8
|
+
/** SHA-256(0x00 || data) */
|
|
9
|
+
export function leafHash(data) {
|
|
10
|
+
const buf = new Uint8Array(1 + data.length);
|
|
11
|
+
buf[0] = LEAF_PREFIX;
|
|
12
|
+
buf.set(data, 1);
|
|
13
|
+
return sha256(buf);
|
|
14
|
+
}
|
|
15
|
+
function nodeHash(left, right) {
|
|
16
|
+
const buf = new Uint8Array(1 + 64);
|
|
17
|
+
buf[0] = NODE_PREFIX;
|
|
18
|
+
buf.set(left, 1);
|
|
19
|
+
buf.set(right, 33);
|
|
20
|
+
return sha256(buf);
|
|
21
|
+
}
|
|
22
|
+
/** Largest power of two strictly less than n (n >= 2). */
|
|
23
|
+
function split(n) {
|
|
24
|
+
let k = 1;
|
|
25
|
+
while (k * 2 < n)
|
|
26
|
+
k *= 2;
|
|
27
|
+
return k;
|
|
28
|
+
}
|
|
29
|
+
// ponytail: recursive slices, O(n log n) per call — swap for an incremental level-cached tree past ~100k leaves
|
|
30
|
+
export function merkleRoot(leafHashes) {
|
|
31
|
+
const n = leafHashes.length;
|
|
32
|
+
if (n === 0)
|
|
33
|
+
return sha256(new Uint8Array(0));
|
|
34
|
+
if (n === 1)
|
|
35
|
+
return leafHashes[0];
|
|
36
|
+
const k = split(n);
|
|
37
|
+
return nodeHash(merkleRoot(leafHashes.slice(0, k)), merkleRoot(leafHashes.slice(k)));
|
|
38
|
+
}
|
|
39
|
+
/** Audit path for leaf `index` in a tree of the given leaf hashes (RFC 6962 §2.1.1). */
|
|
40
|
+
export function inclusionProof(index, leafHashes) {
|
|
41
|
+
const n = leafHashes.length;
|
|
42
|
+
if (!Number.isInteger(index) || index < 0 || index >= n) {
|
|
43
|
+
throw new Error(`leaf index ${index} out of range for tree size ${n}`);
|
|
44
|
+
}
|
|
45
|
+
if (n === 1)
|
|
46
|
+
return [];
|
|
47
|
+
const k = split(n);
|
|
48
|
+
return index < k
|
|
49
|
+
? [...inclusionProof(index, leafHashes.slice(0, k)), merkleRoot(leafHashes.slice(k))]
|
|
50
|
+
: [...inclusionProof(index - k, leafHashes.slice(k)), merkleRoot(leafHashes.slice(0, k))];
|
|
51
|
+
}
|
|
52
|
+
const eq = (a, b) => a.length === b.length && a.every((x, i) => x === b[i]);
|
|
53
|
+
/** RFC 9162 §2.1.3.2. Pure; returns false on any malformed input. */
|
|
54
|
+
export function verifyInclusion(leaf, index, size, proof, root) {
|
|
55
|
+
if (!Number.isInteger(index) || !Number.isInteger(size) || index < 0 || index >= size)
|
|
56
|
+
return false;
|
|
57
|
+
let fn = index;
|
|
58
|
+
let sn = size - 1;
|
|
59
|
+
let r = leaf;
|
|
60
|
+
for (const p of proof) {
|
|
61
|
+
if (p.length !== 32)
|
|
62
|
+
return false;
|
|
63
|
+
if (sn === 0)
|
|
64
|
+
return false;
|
|
65
|
+
if (fn % 2 === 1 || fn === sn) {
|
|
66
|
+
r = nodeHash(p, r);
|
|
67
|
+
if (fn % 2 === 0) {
|
|
68
|
+
while (fn % 2 === 0 && fn !== 0) {
|
|
69
|
+
fn = Math.floor(fn / 2);
|
|
70
|
+
sn = Math.floor(sn / 2);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
r = nodeHash(r, p);
|
|
76
|
+
}
|
|
77
|
+
fn = Math.floor(fn / 2);
|
|
78
|
+
sn = Math.floor(sn / 2);
|
|
79
|
+
}
|
|
80
|
+
return sn === 0 && eq(r, root);
|
|
81
|
+
}
|
|
82
|
+
/** Consistency proof from tree size m to the current tree (RFC 6962 §2.1.2). */
|
|
83
|
+
export function consistencyProof(m, leafHashes) {
|
|
84
|
+
const n = leafHashes.length;
|
|
85
|
+
if (!Number.isInteger(m) || m < 1 || m > n) {
|
|
86
|
+
throw new Error(`old size ${m} out of range for tree size ${n}`);
|
|
87
|
+
}
|
|
88
|
+
if (m === n)
|
|
89
|
+
return [];
|
|
90
|
+
return subproof(m, leafHashes, true);
|
|
91
|
+
}
|
|
92
|
+
function subproof(m, leafHashes, complete) {
|
|
93
|
+
const n = leafHashes.length;
|
|
94
|
+
if (m === n)
|
|
95
|
+
return complete ? [] : [merkleRoot(leafHashes)];
|
|
96
|
+
const k = split(n);
|
|
97
|
+
return m <= k
|
|
98
|
+
? [...subproof(m, leafHashes.slice(0, k), complete), merkleRoot(leafHashes.slice(k))]
|
|
99
|
+
: [...subproof(m - k, leafHashes.slice(k), false), merkleRoot(leafHashes.slice(0, k))];
|
|
100
|
+
}
|
|
101
|
+
/** RFC 9162 §2.1.4.2. Pure; returns false on any malformed input. */
|
|
102
|
+
export function verifyConsistency(size1, size2, root1, root2, proof) {
|
|
103
|
+
if (!Number.isInteger(size1) || !Number.isInteger(size2) || size1 < 0 || size1 > size2)
|
|
104
|
+
return false;
|
|
105
|
+
if (size1 === size2)
|
|
106
|
+
return proof.length === 0 && eq(root1, root2);
|
|
107
|
+
if (size1 === 0)
|
|
108
|
+
return proof.length === 0;
|
|
109
|
+
if (proof.length === 0)
|
|
110
|
+
return false;
|
|
111
|
+
const path = [...proof];
|
|
112
|
+
// If size1 is an exact power of two, root1 is itself the first component.
|
|
113
|
+
if ((size1 & (size1 - 1)) === 0)
|
|
114
|
+
path.unshift(root1);
|
|
115
|
+
let fn = size1 - 1;
|
|
116
|
+
let sn = size2 - 1;
|
|
117
|
+
while (fn % 2 === 1) {
|
|
118
|
+
fn = Math.floor(fn / 2);
|
|
119
|
+
sn = Math.floor(sn / 2);
|
|
120
|
+
}
|
|
121
|
+
let fr = path[0];
|
|
122
|
+
let sr = path[0];
|
|
123
|
+
for (const c of path.slice(1)) {
|
|
124
|
+
if (c.length !== 32)
|
|
125
|
+
return false;
|
|
126
|
+
if (sn === 0)
|
|
127
|
+
return false;
|
|
128
|
+
if (fn % 2 === 1 || fn === sn) {
|
|
129
|
+
fr = nodeHash(c, fr);
|
|
130
|
+
sr = nodeHash(c, sr);
|
|
131
|
+
if (fn % 2 === 0) {
|
|
132
|
+
while (fn % 2 === 0 && fn !== 0) {
|
|
133
|
+
fn = Math.floor(fn / 2);
|
|
134
|
+
sn = Math.floor(sn / 2);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
sr = nodeHash(sr, c);
|
|
140
|
+
}
|
|
141
|
+
fn = Math.floor(fn / 2);
|
|
142
|
+
sn = Math.floor(sn / 2);
|
|
143
|
+
}
|
|
144
|
+
return sn === 0 && eq(fr, root1) && eq(sr, root2);
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=merkle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merkle.js","sourceRoot":"","sources":["../src/merkle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type DelegationCert } from './delegation.js';
|
|
2
|
+
export interface Receipt {
|
|
3
|
+
v: 1;
|
|
4
|
+
agent_id: string;
|
|
5
|
+
delegation: DelegationCert[];
|
|
6
|
+
action: string;
|
|
7
|
+
target: string;
|
|
8
|
+
payload_hash: string;
|
|
9
|
+
ts: string;
|
|
10
|
+
prev: string | null;
|
|
11
|
+
sig: string;
|
|
12
|
+
}
|
|
13
|
+
export interface VerifyResult {
|
|
14
|
+
ok: boolean;
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function hashPayload(payload: Uint8Array | string): string;
|
|
18
|
+
export declare function createReceipt(fields: {
|
|
19
|
+
agentId: string;
|
|
20
|
+
delegation: DelegationCert[];
|
|
21
|
+
action: string;
|
|
22
|
+
target: string;
|
|
23
|
+
payloadHash: string;
|
|
24
|
+
ts: string;
|
|
25
|
+
prev: string | null;
|
|
26
|
+
}, agentPrivateKey: Uint8Array): Receipt;
|
|
27
|
+
/** Hash of the full receipt (incl. sig) — what the next receipt's `prev` points to. */
|
|
28
|
+
export declare function receiptHash(receipt: Receipt): string;
|
|
29
|
+
export declare function verifyReceiptSignature(receipt: Receipt): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Full single-receipt verification per SPEC §4:
|
|
32
|
+
* signature → delegation chain (at receipt time) → scope covers target → prev linkage.
|
|
33
|
+
*/
|
|
34
|
+
export declare function verifyReceipt(receipt: Receipt, opts?: {
|
|
35
|
+
expectedOwner?: string;
|
|
36
|
+
revoked?: Set<string>;
|
|
37
|
+
expectedPrev?: string | null;
|
|
38
|
+
}): VerifyResult;
|
|
39
|
+
/**
|
|
40
|
+
* Verify an agent's full receipt sequence: every receipt valid and hash-linked
|
|
41
|
+
* to the one before it. Returns the index of the first bad receipt on failure.
|
|
42
|
+
*/
|
|
43
|
+
export declare function verifyReceiptChain(receipts: Receipt[], opts?: {
|
|
44
|
+
expectedOwner?: string;
|
|
45
|
+
revoked?: Set<string>;
|
|
46
|
+
}): VerifyResult & {
|
|
47
|
+
failedIndex?: number;
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=receipt.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/receipt.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ed25519 } from '@noble/curves/ed25519';
|
|
2
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
3
|
+
import { bytesToHex } from '@noble/hashes/utils';
|
|
4
|
+
import { canonicalBytes, decodeSig, encodeSig, jcsHash } from './encoding.js';
|
|
5
|
+
import { publicKeyFromDid } from './keys.js';
|
|
6
|
+
import { scopesAllow, verifyChain } from './delegation.js';
|
|
7
|
+
export function hashPayload(payload) {
|
|
8
|
+
const bytes = typeof payload === 'string' ? new TextEncoder().encode(payload) : payload;
|
|
9
|
+
return `sha256:${bytesToHex(sha256(bytes))}`;
|
|
10
|
+
}
|
|
11
|
+
export function createReceipt(fields, agentPrivateKey) {
|
|
12
|
+
if (Number.isNaN(Date.parse(fields.ts)))
|
|
13
|
+
throw new Error(`invalid ts timestamp: ${fields.ts}`);
|
|
14
|
+
const unsigned = {
|
|
15
|
+
v: 1,
|
|
16
|
+
agent_id: fields.agentId,
|
|
17
|
+
delegation: fields.delegation,
|
|
18
|
+
action: fields.action,
|
|
19
|
+
target: fields.target,
|
|
20
|
+
payload_hash: fields.payloadHash,
|
|
21
|
+
ts: fields.ts,
|
|
22
|
+
prev: fields.prev,
|
|
23
|
+
};
|
|
24
|
+
const sig = ed25519.sign(canonicalBytes(unsigned), agentPrivateKey);
|
|
25
|
+
return { ...unsigned, sig: encodeSig(sig) };
|
|
26
|
+
}
|
|
27
|
+
/** Hash of the full receipt (incl. sig) — what the next receipt's `prev` points to. */
|
|
28
|
+
export function receiptHash(receipt) {
|
|
29
|
+
return jcsHash(receipt);
|
|
30
|
+
}
|
|
31
|
+
export function verifyReceiptSignature(receipt) {
|
|
32
|
+
const pub = publicKeyFromDid(receipt.agent_id);
|
|
33
|
+
const sig = decodeSig(receipt.sig);
|
|
34
|
+
if (!pub || !sig)
|
|
35
|
+
return false;
|
|
36
|
+
const { sig: _omitted, ...unsigned } = receipt;
|
|
37
|
+
try {
|
|
38
|
+
return ed25519.verify(sig, canonicalBytes(unsigned), pub);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Full single-receipt verification per SPEC §4:
|
|
46
|
+
* signature → delegation chain (at receipt time) → scope covers target → prev linkage.
|
|
47
|
+
*/
|
|
48
|
+
export function verifyReceipt(receipt, opts = {}) {
|
|
49
|
+
if (receipt.v !== 1)
|
|
50
|
+
return { ok: false, error: 'unsupported receipt version' };
|
|
51
|
+
if (!verifyReceiptSignature(receipt))
|
|
52
|
+
return { ok: false, error: 'bad receipt signature' };
|
|
53
|
+
const ts = new Date(receipt.ts);
|
|
54
|
+
if (Number.isNaN(ts.getTime()))
|
|
55
|
+
return { ok: false, error: 'invalid ts' };
|
|
56
|
+
const chain = verifyChain(receipt.delegation, {
|
|
57
|
+
agentId: receipt.agent_id,
|
|
58
|
+
expectedRoot: opts.expectedOwner,
|
|
59
|
+
revoked: opts.revoked,
|
|
60
|
+
at: ts,
|
|
61
|
+
});
|
|
62
|
+
if (!chain.ok)
|
|
63
|
+
return { ok: false, error: `delegation: ${chain.error}` };
|
|
64
|
+
if (!scopesAllow(chain.effectiveScopes, receipt.target)) {
|
|
65
|
+
return { ok: false, error: `target ${receipt.target} outside effective scopes` };
|
|
66
|
+
}
|
|
67
|
+
if (opts.expectedPrev !== undefined && receipt.prev !== opts.expectedPrev) {
|
|
68
|
+
return { ok: false, error: 'prev hash does not match preceding receipt (chain broken)' };
|
|
69
|
+
}
|
|
70
|
+
return { ok: true };
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Verify an agent's full receipt sequence: every receipt valid and hash-linked
|
|
74
|
+
* to the one before it. Returns the index of the first bad receipt on failure.
|
|
75
|
+
*/
|
|
76
|
+
export function verifyReceiptChain(receipts, opts = {}) {
|
|
77
|
+
let expectedPrev = null;
|
|
78
|
+
for (let i = 0; i < receipts.length; i++) {
|
|
79
|
+
const r = receipts[i];
|
|
80
|
+
const result = verifyReceipt(r, { ...opts, expectedPrev });
|
|
81
|
+
if (!result.ok)
|
|
82
|
+
return { ok: false, error: `receipt ${i}: ${result.error}`, failedIndex: i };
|
|
83
|
+
expectedPrev = receiptHash(r);
|
|
84
|
+
}
|
|
85
|
+
return { ok: true };
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=receipt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receipt.js","sourceRoot":"","sources":["../src/receipt.ts"],"names":[],"mappings":"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"}
|
package/dist/sth.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Signed Tree Head — the log's periodic, signed commitment to its state (SPEC §5). */
|
|
2
|
+
export interface SignedTreeHead {
|
|
3
|
+
v: 1;
|
|
4
|
+
log_id: string;
|
|
5
|
+
size: number;
|
|
6
|
+
root: string;
|
|
7
|
+
ts: string;
|
|
8
|
+
sig: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function createSTH(fields: {
|
|
11
|
+
logId: string;
|
|
12
|
+
size: number;
|
|
13
|
+
root: string;
|
|
14
|
+
ts: string;
|
|
15
|
+
}, logPrivateKey: Uint8Array): SignedTreeHead;
|
|
16
|
+
export declare function verifySTH(sth: SignedTreeHead): boolean;
|
|
17
|
+
//# sourceMappingURL=sth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sth.d.ts","sourceRoot":"","sources":["../src/sth.ts"],"names":[],"mappings":"AAIA,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,CAAC,EAAE,CAAC,CAAC;IACL,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,SAAS,CACvB,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EACjE,aAAa,EAAE,UAAU,GACxB,cAAc,CAIhB;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAWtD"}
|
package/dist/sth.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ed25519 } from '@noble/curves/ed25519';
|
|
2
|
+
import { canonicalBytes, decodeSig, encodeSig } from './encoding.js';
|
|
3
|
+
import { publicKeyFromDid } from './keys.js';
|
|
4
|
+
export function createSTH(fields, logPrivateKey) {
|
|
5
|
+
const unsigned = { v: 1, log_id: fields.logId, size: fields.size, root: fields.root, ts: fields.ts };
|
|
6
|
+
const sig = ed25519.sign(canonicalBytes(unsigned), logPrivateKey);
|
|
7
|
+
return { ...unsigned, sig: encodeSig(sig) };
|
|
8
|
+
}
|
|
9
|
+
export function verifySTH(sth) {
|
|
10
|
+
if (sth.v !== 1 || !Number.isInteger(sth.size) || sth.size < 0)
|
|
11
|
+
return false;
|
|
12
|
+
const pub = publicKeyFromDid(sth.log_id);
|
|
13
|
+
const sig = decodeSig(sth.sig);
|
|
14
|
+
if (!pub || !sig)
|
|
15
|
+
return false;
|
|
16
|
+
const { sig: _omitted, ...unsigned } = sth;
|
|
17
|
+
try {
|
|
18
|
+
return ed25519.verify(sig, canonicalBytes(unsigned), pub);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=sth.js.map
|
package/dist/sth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sth.js","sourceRoot":"","sources":["../src/sth.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;AAY7C,MAAM,UAAU,SAAS,CACvB,MAAiE,EACjE,aAAyB;IAEzB,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,CAAU,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;IAC9G,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAC;IAClE,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAmB;IAC3C,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7E,MAAM,GAAG,GAAG,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,GAAG,GAAG,CAAC;IAC3C,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"}
|