@agenticprimitives/verifiable-credentials 0.0.0-alpha.2

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Agentic Trust Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # @agenticprimitives/verifiable-credentials
2
+
3
+ > **Status:** STUB (Wave 0.5 of the W1 implementation wave). Implementation lands in subsequent waves per [docs/architecture/w1-implementation-wave-plan.md](../../docs/architecture/w1-implementation-wave-plan.md).
4
+
5
+ W3C Verifiable Credentials envelope + Eip712Signature2026 proof + DOLCE+DnS Situation bases + ontology-shape schema registration. Substrate for layers 12–15 credential types.
6
+
7
+ **Owns spine layers:** envelope.
8
+ **Authoritative spec:** [`specs/242-*.md`](../../specs/) — see `spec.md` for the symlink to the canonical spec.
9
+
10
+ ## What this package will own
11
+
12
+ See `CLAUDE.md` and `capability.manifest.json` for the bounded surface.
13
+
14
+ ## Build
15
+
16
+ ```bash
17
+ pnpm --filter @agenticprimitives/verifiable-credentials typecheck
18
+ pnpm --filter @agenticprimitives/verifiable-credentials test
19
+ pnpm --filter @agenticprimitives/verifiable-credentials build
20
+ ```
@@ -0,0 +1,34 @@
1
+ /**
2
+ * RFC 8785 JSON Canonicalization Scheme (JCS) — deterministic JSON serialisation
3
+ * for cross-stack hash equality (TS ↔ Solidity ↔ Java/Go verifiers).
4
+ *
5
+ * The substrate's `credentialHash` is `keccak256(jcsCanonicalize(vc-without-proof))`.
6
+ * Every package that needs to recompute the hash MUST go through this helper.
7
+ *
8
+ * RFC 8785 rules:
9
+ * - UTF-8 strings, NFC normalisation (browsers ship NFC already)
10
+ * - Object keys sorted by UTF-16 code unit (== lexicographic in BMP)
11
+ * - No insignificant whitespace
12
+ * - Numbers as the shortest IEEE 754 round-trip representation
13
+ * - Booleans `true` / `false` / `null` lowercase
14
+ * - Strings JSON-escape U+0000..U+001F, U+0022, U+005C only; emit other code points as-is
15
+ *
16
+ * This implementation is intentionally narrow: substrate VCs use a constrained
17
+ * subset of JSON (string / number / boolean / null / object / array). We do not
18
+ * handle BigInt or Date — callers must serialise those upstream.
19
+ */
20
+ export declare class JcsError extends Error {
21
+ readonly path: string;
22
+ constructor(message: string, path: string);
23
+ }
24
+ /**
25
+ * Canonicalize a JSON-compatible value per RFC 8785.
26
+ * Returns the canonical string (UTF-8 text; callers wrap with `utf8ToBytes` to hash).
27
+ */
28
+ export declare function jcsCanonicalize(value: unknown, path?: string): string;
29
+ /**
30
+ * Compute the canonical hash of a value: `keccak256(jcsCanonicalize(value))`.
31
+ * Returns the 32-byte hex hash.
32
+ */
33
+ export declare function canonicalHash(value: unknown): `0x${string}`;
34
+ //# sourceMappingURL=canonical.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../src/canonical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,qBAAa,QAAS,SAAQ,KAAK;IACJ,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAAtC,OAAO,EAAE,MAAM,EAAW,IAAI,EAAE,MAAM;CAGnD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,GAAE,MAAY,GAAG,MAAM,CA2B1E;AAkED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,MAAM,EAAE,CAK3D"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * RFC 8785 JSON Canonicalization Scheme (JCS) — deterministic JSON serialisation
3
+ * for cross-stack hash equality (TS ↔ Solidity ↔ Java/Go verifiers).
4
+ *
5
+ * The substrate's `credentialHash` is `keccak256(jcsCanonicalize(vc-without-proof))`.
6
+ * Every package that needs to recompute the hash MUST go through this helper.
7
+ *
8
+ * RFC 8785 rules:
9
+ * - UTF-8 strings, NFC normalisation (browsers ship NFC already)
10
+ * - Object keys sorted by UTF-16 code unit (== lexicographic in BMP)
11
+ * - No insignificant whitespace
12
+ * - Numbers as the shortest IEEE 754 round-trip representation
13
+ * - Booleans `true` / `false` / `null` lowercase
14
+ * - Strings JSON-escape U+0000..U+001F, U+0022, U+005C only; emit other code points as-is
15
+ *
16
+ * This implementation is intentionally narrow: substrate VCs use a constrained
17
+ * subset of JSON (string / number / boolean / null / object / array). We do not
18
+ * handle BigInt or Date — callers must serialise those upstream.
19
+ */
20
+ import { keccak_256 } from '@noble/hashes/sha3.js';
21
+ import { utf8ToBytes } from '@noble/hashes/utils.js';
22
+ export class JcsError extends Error {
23
+ path;
24
+ constructor(message, path) {
25
+ super(`[JCS] ${message} at ${path}`);
26
+ this.path = path;
27
+ }
28
+ }
29
+ /**
30
+ * Canonicalize a JSON-compatible value per RFC 8785.
31
+ * Returns the canonical string (UTF-8 text; callers wrap with `utf8ToBytes` to hash).
32
+ */
33
+ export function jcsCanonicalize(value, path = '$') {
34
+ if (value === null)
35
+ return 'null';
36
+ if (value === undefined) {
37
+ throw new JcsError('undefined is not JSON', path);
38
+ }
39
+ switch (typeof value) {
40
+ case 'boolean':
41
+ return value ? 'true' : 'false';
42
+ case 'string':
43
+ return serializeString(value);
44
+ case 'number':
45
+ return serializeNumber(value, path);
46
+ case 'object': {
47
+ if (Array.isArray(value)) {
48
+ const items = value.map((v, i) => jcsCanonicalize(v, `${path}[${i}]`));
49
+ return `[${items.join(',')}]`;
50
+ }
51
+ // Plain object
52
+ const entries = Object.entries(value)
53
+ .filter(([, v]) => v !== undefined)
54
+ .sort(([a], [b]) => sortByCodeUnit(a, b));
55
+ const items = entries.map(([k, v]) => `${serializeString(k)}:${jcsCanonicalize(v, `${path}.${k}`)}`);
56
+ return `{${items.join(',')}}`;
57
+ }
58
+ default:
59
+ throw new JcsError(`unsupported JSON type: ${typeof value}`, path);
60
+ }
61
+ }
62
+ /** UTF-16 code unit comparison — exactly what RFC 8785 §3.2.3 requires. */
63
+ function sortByCodeUnit(a, b) {
64
+ const len = Math.min(a.length, b.length);
65
+ for (let i = 0; i < len; i++) {
66
+ const av = a.charCodeAt(i);
67
+ const bv = b.charCodeAt(i);
68
+ if (av !== bv)
69
+ return av - bv;
70
+ }
71
+ return a.length - b.length;
72
+ }
73
+ /** RFC 8259 string serialisation with JCS-compatible escaping (RFC 8785 §3.2.2.2). */
74
+ function serializeString(s) {
75
+ let out = '"';
76
+ for (let i = 0; i < s.length; i++) {
77
+ const code = s.charCodeAt(i);
78
+ if (code === 0x22) {
79
+ out += '\\"';
80
+ }
81
+ else if (code === 0x5c) {
82
+ out += '\\\\';
83
+ }
84
+ else if (code < 0x20) {
85
+ // Control characters
86
+ switch (code) {
87
+ case 0x08:
88
+ out += '\\b';
89
+ break;
90
+ case 0x09:
91
+ out += '\\t';
92
+ break;
93
+ case 0x0a:
94
+ out += '\\n';
95
+ break;
96
+ case 0x0c:
97
+ out += '\\f';
98
+ break;
99
+ case 0x0d:
100
+ out += '\\r';
101
+ break;
102
+ default:
103
+ out += `\\u${code.toString(16).padStart(4, '0')}`;
104
+ }
105
+ }
106
+ else {
107
+ out += s[i];
108
+ }
109
+ }
110
+ out += '"';
111
+ return out;
112
+ }
113
+ /** RFC 8785 §3.2.2.3 — shortest round-tripping IEEE 754 representation. */
114
+ function serializeNumber(n, path) {
115
+ if (!Number.isFinite(n)) {
116
+ throw new JcsError(`non-finite number (${n})`, path);
117
+ }
118
+ if (Object.is(n, -0))
119
+ return '0';
120
+ if (n === 0)
121
+ return '0';
122
+ if (Number.isInteger(n) && Math.abs(n) < 1e21) {
123
+ return n.toString();
124
+ }
125
+ // Browsers + Node give us the shortest round-trip via `toString()`
126
+ // (per ECMA-262 §6.1.6.1.13). RFC 8785 expects the ES round-trip form.
127
+ return n.toString();
128
+ }
129
+ /**
130
+ * Compute the canonical hash of a value: `keccak256(jcsCanonicalize(value))`.
131
+ * Returns the 32-byte hex hash.
132
+ */
133
+ export function canonicalHash(value) {
134
+ const canonical = jcsCanonicalize(value);
135
+ const bytes = utf8ToBytes(canonical);
136
+ const digest = keccak_256(bytes);
137
+ return `0x${bytesToHex(digest)}`;
138
+ }
139
+ function bytesToHex(b) {
140
+ let s = '';
141
+ for (const v of b) {
142
+ s += v.toString(16).padStart(2, '0');
143
+ }
144
+ return s;
145
+ }
146
+ //# sourceMappingURL=canonical.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.js","sourceRoot":"","sources":["../src/canonical.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @agenticprimitives/verifiable-credentials — W3C VC 2.0 envelope, EIP-712
3
+ * + ERC-1271 proof, DOLCE+DnS Situation bases, JCS canonical hash, and the
4
+ * schema-registration helper.
5
+ *
6
+ * Substrate for spine layers 12–15 credential classes; consumers (attestations,
7
+ * agreements, payments, fulfillment) compose specific credential types on top.
8
+ *
9
+ * Authoritative spec: specs/242-trust-credentials-and-public-assertions.md
10
+ */
11
+ export declare const PACKAGE_NAME = "@agenticprimitives/verifiable-credentials";
12
+ export declare const PACKAGE_STATUS: "w1-foundational";
13
+ export declare const SPEC_REF = "specs/242-trust-credentials-and-public-assertions.md";
14
+ export { VC_CONTEXT_V2, EIP712_SIG_2026_CONTEXT, VC_DOMAIN_NAME, VC_DOMAIN_VERSION, VC_EIP712_TYPES, } from './types.js';
15
+ export type { Hex32, ISODate, ProofType, Eip712Signature2026Proof, Proof, CredentialStatus2021, VisibilityTier, DisclosurePolicy, VerifiableCredential, UnsignedCredential, } from './types.js';
16
+ export { jcsCanonicalize, canonicalHash, JcsError } from './canonical.js';
17
+ export { assertSituationRolesPresent, buildSituation, } from './situation.js';
18
+ export type { Situation, DescriptionRef, RoleName } from './situation.js';
19
+ export { credentialHash, eip712Digest, isoToSeconds, signCredential, viemSignerFromWallet, } from './proof.js';
20
+ export type { CredentialSigner } from './proof.js';
21
+ export { verifyCredentialStructural } from './verifier.js';
22
+ export type { VerificationResult } from './verifier.js';
23
+ export { SHAPE_DID_PREFIX, buildShapeUri, parseShapeUri, shapeHash } from './schema.js';
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,eAAO,MAAM,YAAY,8CAA8C,CAAC;AACxE,eAAO,MAAM,cAAc,EAAG,iBAA0B,CAAC;AACzD,eAAO,MAAM,QAAQ,yDAAyD,CAAC;AAG/E,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,KAAK,EACL,OAAO,EACP,SAAS,EACT,wBAAwB,EACxB,KAAK,EACL,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG1E,OAAO,EACL,2BAA2B,EAC3B,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG1E,OAAO,EACL,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGxD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @agenticprimitives/verifiable-credentials — W3C VC 2.0 envelope, EIP-712
3
+ * + ERC-1271 proof, DOLCE+DnS Situation bases, JCS canonical hash, and the
4
+ * schema-registration helper.
5
+ *
6
+ * Substrate for spine layers 12–15 credential classes; consumers (attestations,
7
+ * agreements, payments, fulfillment) compose specific credential types on top.
8
+ *
9
+ * Authoritative spec: specs/242-trust-credentials-and-public-assertions.md
10
+ */
11
+ export const PACKAGE_NAME = '@agenticprimitives/verifiable-credentials';
12
+ export const PACKAGE_STATUS = 'w1-foundational';
13
+ export const SPEC_REF = 'specs/242-trust-credentials-and-public-assertions.md';
14
+ // Types + constants
15
+ export { VC_CONTEXT_V2, EIP712_SIG_2026_CONTEXT, VC_DOMAIN_NAME, VC_DOMAIN_VERSION, VC_EIP712_TYPES, } from './types.js';
16
+ // Canonical hash + JCS
17
+ export { jcsCanonicalize, canonicalHash, JcsError } from './canonical.js';
18
+ // Situation pattern
19
+ export { assertSituationRolesPresent, buildSituation, } from './situation.js';
20
+ // Proof builder
21
+ export { credentialHash, eip712Digest, isoToSeconds, signCredential, viemSignerFromWallet, } from './proof.js';
22
+ // Verifier
23
+ export { verifyCredentialStructural } from './verifier.js';
24
+ // Schema registration
25
+ export { SHAPE_DID_PREFIX, buildShapeUri, parseShapeUri, shapeHash } from './schema.js';
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,2CAA2C,CAAC;AACxE,MAAM,CAAC,MAAM,cAAc,GAAG,iBAA0B,CAAC;AACzD,MAAM,CAAC,MAAM,QAAQ,GAAG,sDAAsD,CAAC;AAE/E,oBAAoB;AACpB,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,eAAe,GAChB,MAAM,YAAY,CAAC;AAcpB,uBAAuB;AACvB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1E,oBAAoB;AACpB,OAAO,EACL,2BAA2B,EAC3B,cAAc,GACf,MAAM,gBAAgB,CAAC;AAGxB,gBAAgB;AAChB,OAAO,EACL,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAGpB,WAAW;AACX,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAG3D,sBAAsB;AACtB,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Eip712Signature2026 proof builder — signs the canonical hash of a credential
3
+ * subject + envelope metadata with EIP-712 typed data, producing an
4
+ * ERC-1271-verifiable signature.
5
+ *
6
+ * Spec 242 §4.3 + ADR-0023 §D2.
7
+ */
8
+ import { type Address, type Hex, type WalletClient } from 'viem';
9
+ import { type Eip712Signature2026Proof, type Hex32, type Proof, type UnsignedCredential, type VerifiableCredential } from './types.js';
10
+ /** A signer abstraction so callers can wire viem wallet client OR a custom signer. */
11
+ export interface CredentialSigner {
12
+ /** Address of the SA that will be the issuer (verified via ERC-1271). */
13
+ issuerAddress: Address;
14
+ /** EIP-712 chain id + verifying-contract anchor for the SA. */
15
+ chainId: number;
16
+ /** Must match the SA's verifying contract (typically the SA itself for ERC-1271). */
17
+ verifyingContract: Address;
18
+ /**
19
+ * Sign an arbitrary 32-byte digest. Implementations route through whatever
20
+ * the SA's signing path is (passkey, EOA wrap, KMS, multi-sig, etc.).
21
+ */
22
+ signDigest(digest: Hex32): Promise<Hex>;
23
+ }
24
+ /**
25
+ * Compute the canonical hash of an unsigned credential — strips `proof`,
26
+ * applies RFC 8785 JCS canonicalisation, returns keccak256.
27
+ */
28
+ export declare function credentialHash(unsigned: UnsignedCredential | VerifiableCredential): Hex32;
29
+ /**
30
+ * Compute the EIP-712 typed-data digest the signer signs. Cross-stack typehash
31
+ * equality test (spec 242 §4.3) verifies this matches a Solidity verifier.
32
+ */
33
+ export declare function eip712Digest(args: {
34
+ credentialBodyHash: Hex32;
35
+ issuer: string;
36
+ validFrom: number;
37
+ validUntil: number;
38
+ proofPurpose: Eip712Signature2026Proof['proofPurpose'];
39
+ chainId: number;
40
+ verifyingContract: Address;
41
+ }): Hex32;
42
+ /** Convert an ISO-8601 timestamp to a uint64-safe seconds value. */
43
+ export declare function isoToSeconds(iso: string | undefined): number;
44
+ /**
45
+ * Sign an `UnsignedCredential` and return a fully formed `VerifiableCredential`.
46
+ */
47
+ export declare function signCredential<TSubject extends Record<string, unknown>>(unsigned: UnsignedCredential<TSubject>, signer: CredentialSigner, opts?: {
48
+ proofPurpose?: Eip712Signature2026Proof['proofPurpose'];
49
+ }): Promise<VerifiableCredential<TSubject>>;
50
+ /** Convenience: a viem `WalletClient`-backed `CredentialSigner` (EOA-only path). */
51
+ export declare function viemSignerFromWallet(args: {
52
+ wallet: WalletClient;
53
+ issuerAddress: Address;
54
+ chainId: number;
55
+ verifyingContract: Address;
56
+ }): CredentialSigner;
57
+ /** Re-export so callers see the Proof union from one place. */
58
+ export type { Proof };
59
+ //# sourceMappingURL=proof.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proof.d.ts","sourceRoot":"","sources":["../src/proof.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAiB,KAAK,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,YAAY,EAAE,MAAM,MAAM,CAAC;AAGhF,OAAO,EAML,KAAK,wBAAwB,EAC7B,KAAK,KAAK,EACV,KAAK,KAAK,EACV,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAC;AAEpB,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,aAAa,EAAE,OAAO,CAAC;IACvB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,iBAAiB,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CACzC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,kBAAkB,GAAG,oBAAoB,GAAG,KAAK,CAKzF;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,kBAAkB,EAAE,KAAK,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC,cAAc,CAAC,CAAC;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,OAAO,CAAC;CAC5B,GAAG,KAAK,CAkBR;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAG5D;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3E,QAAQ,EAAE,kBAAkB,CAAC,QAAQ,CAAC,EACtC,MAAM,EAAE,gBAAgB,EACxB,IAAI,GAAE;IAAE,YAAY,CAAC,EAAE,wBAAwB,CAAC,cAAc,CAAC,CAAA;CAAO,GACrE,OAAO,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAkCzC;AAED,oFAAoF;AACpF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,OAAO,CAAC;CAC5B,GAAG,gBAAgB,CAYnB;AAQD,+DAA+D;AAC/D,YAAY,EAAE,KAAK,EAAE,CAAC"}
package/dist/proof.js ADDED
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Eip712Signature2026 proof builder — signs the canonical hash of a credential
3
+ * subject + envelope metadata with EIP-712 typed data, producing an
4
+ * ERC-1271-verifiable signature.
5
+ *
6
+ * Spec 242 §4.3 + ADR-0023 §D2.
7
+ */
8
+ import { hashTypedData } from 'viem';
9
+ import { canonicalHash } from './canonical.js';
10
+ import { EIP712_SIG_2026_CONTEXT, VC_CONTEXT_V2, VC_DOMAIN_NAME, VC_DOMAIN_VERSION, VC_EIP712_TYPES, } from './types.js';
11
+ /**
12
+ * Compute the canonical hash of an unsigned credential — strips `proof`,
13
+ * applies RFC 8785 JCS canonicalisation, returns keccak256.
14
+ */
15
+ export function credentialHash(unsigned) {
16
+ // Defensive: strip proof if a signed VC was passed in.
17
+ const { proof: _ignored, ...withoutProof } = unsigned;
18
+ void _ignored;
19
+ return canonicalHash(withoutProof);
20
+ }
21
+ /**
22
+ * Compute the EIP-712 typed-data digest the signer signs. Cross-stack typehash
23
+ * equality test (spec 242 §4.3) verifies this matches a Solidity verifier.
24
+ */
25
+ export function eip712Digest(args) {
26
+ return hashTypedData({
27
+ domain: {
28
+ name: VC_DOMAIN_NAME,
29
+ version: VC_DOMAIN_VERSION,
30
+ chainId: args.chainId,
31
+ verifyingContract: args.verifyingContract,
32
+ },
33
+ types: VC_EIP712_TYPES,
34
+ primaryType: 'VerifiableCredentialAttestation',
35
+ message: {
36
+ credentialHash: args.credentialBodyHash,
37
+ issuer: args.issuer,
38
+ validFrom: BigInt(args.validFrom),
39
+ validUntil: BigInt(args.validUntil),
40
+ proofPurpose: args.proofPurpose,
41
+ },
42
+ });
43
+ }
44
+ /** Convert an ISO-8601 timestamp to a uint64-safe seconds value. */
45
+ export function isoToSeconds(iso) {
46
+ if (!iso)
47
+ return 0;
48
+ return Math.floor(new Date(iso).getTime() / 1000);
49
+ }
50
+ /**
51
+ * Sign an `UnsignedCredential` and return a fully formed `VerifiableCredential`.
52
+ */
53
+ export async function signCredential(unsigned, signer, opts = {}) {
54
+ const proofPurpose = opts.proofPurpose ?? 'assertionMethod';
55
+ const bodyHash = credentialHash(unsigned);
56
+ const digest = eip712Digest({
57
+ credentialBodyHash: bodyHash,
58
+ issuer: unsigned.issuer,
59
+ validFrom: isoToSeconds(unsigned.validFrom),
60
+ validUntil: isoToSeconds(unsigned.validUntil),
61
+ proofPurpose,
62
+ chainId: signer.chainId,
63
+ verifyingContract: signer.verifyingContract,
64
+ });
65
+ const proofValue = await signer.signDigest(digest);
66
+ const proof = {
67
+ type: 'Eip712Signature2026',
68
+ created: new Date().toISOString(),
69
+ verificationMethod: `eip155:${signer.chainId}:${signer.verifyingContract}#assertion-key-1`,
70
+ proofPurpose,
71
+ proofValue,
72
+ eip712Domain: {
73
+ name: VC_DOMAIN_NAME,
74
+ version: VC_DOMAIN_VERSION,
75
+ chainId: signer.chainId,
76
+ verifyingContract: signer.verifyingContract,
77
+ },
78
+ credentialHash: bodyHash,
79
+ };
80
+ return {
81
+ ...unsigned,
82
+ '@context': ensureContexts(unsigned['@context']),
83
+ proof,
84
+ };
85
+ }
86
+ /** Convenience: a viem `WalletClient`-backed `CredentialSigner` (EOA-only path). */
87
+ export function viemSignerFromWallet(args) {
88
+ return {
89
+ issuerAddress: args.issuerAddress,
90
+ chainId: args.chainId,
91
+ verifyingContract: args.verifyingContract,
92
+ async signDigest(digest) {
93
+ return args.wallet.request({
94
+ method: 'eth_sign',
95
+ params: [args.issuerAddress, digest],
96
+ });
97
+ },
98
+ };
99
+ }
100
+ function ensureContexts(existing) {
101
+ const needed = [VC_CONTEXT_V2, EIP712_SIG_2026_CONTEXT];
102
+ const have = new Set(existing);
103
+ return [...existing, ...needed.filter((c) => !have.has(c))];
104
+ }
105
+ //# sourceMappingURL=proof.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proof.js","sourceRoot":"","sources":["../src/proof.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Schema registration helper — produces the `did:shape:<name>:<version>` ↔
3
+ * on-chain `ShapeRegistry.defineShape(...)` round-trip per PD-12.
4
+ *
5
+ * In W1 this module ships pure helpers (no on-chain call). The caller wires
6
+ * the actual `defineShape` call against their viem clients; we provide:
7
+ * - the canonical schema URI form (`did:shape:<name>:<version>`)
8
+ * - the canonical hash bytes (`keccak256` of the canonical SHACL string)
9
+ * - a parser to round-trip schema URIs
10
+ */
11
+ import type { Hex32 } from './types.js';
12
+ export declare const SHAPE_DID_PREFIX: "did:shape:";
13
+ /**
14
+ * Build the canonical `did:shape:<name>:<version>` URI.
15
+ *
16
+ * @throws if name or version contains characters outside `[A-Za-z0-9-_.]`.
17
+ */
18
+ export declare function buildShapeUri(name: string, version: string): string;
19
+ /**
20
+ * Parse a `did:shape:<name>:<version>` URI.
21
+ */
22
+ export declare function parseShapeUri(uri: string): {
23
+ name: string;
24
+ version: string;
25
+ } | null;
26
+ /**
27
+ * Canonicalise SHACL bytes for the on-chain hash. The canonical form is:
28
+ * - UTF-8 normalised (callers are responsible for upstream NFC if needed)
29
+ * - keccak256 of the raw bytes
30
+ *
31
+ * This matches the on-chain `ShapeRegistry.defineShape(shapeHash)` expectation
32
+ * — both sides hash the exact same SHACL string.
33
+ */
34
+ export declare function shapeHash(shaclBytes: string | Uint8Array): Hex32;
35
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,eAAO,MAAM,gBAAgB,EAAG,YAAqB,CAAC;AAEtD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAQnE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CASnF;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,KAAK,CAQhE"}
package/dist/schema.js ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Schema registration helper — produces the `did:shape:<name>:<version>` ↔
3
+ * on-chain `ShapeRegistry.defineShape(...)` round-trip per PD-12.
4
+ *
5
+ * In W1 this module ships pure helpers (no on-chain call). The caller wires
6
+ * the actual `defineShape` call against their viem clients; we provide:
7
+ * - the canonical schema URI form (`did:shape:<name>:<version>`)
8
+ * - the canonical hash bytes (`keccak256` of the canonical SHACL string)
9
+ * - a parser to round-trip schema URIs
10
+ */
11
+ import { keccak_256 } from '@noble/hashes/sha3.js';
12
+ import { utf8ToBytes } from '@noble/hashes/utils.js';
13
+ export const SHAPE_DID_PREFIX = 'did:shape:';
14
+ /**
15
+ * Build the canonical `did:shape:<name>:<version>` URI.
16
+ *
17
+ * @throws if name or version contains characters outside `[A-Za-z0-9-_.]`.
18
+ */
19
+ export function buildShapeUri(name, version) {
20
+ if (!/^[A-Za-z0-9._-]+$/.test(name)) {
21
+ throw new Error(`[verifiable-credentials/schema] invalid shape name: ${name}`);
22
+ }
23
+ if (!/^[A-Za-z0-9._-]+$/.test(version)) {
24
+ throw new Error(`[verifiable-credentials/schema] invalid shape version: ${version}`);
25
+ }
26
+ return `${SHAPE_DID_PREFIX}${name}:${version}`;
27
+ }
28
+ /**
29
+ * Parse a `did:shape:<name>:<version>` URI.
30
+ */
31
+ export function parseShapeUri(uri) {
32
+ if (!uri.startsWith(SHAPE_DID_PREFIX))
33
+ return null;
34
+ const body = uri.slice(SHAPE_DID_PREFIX.length);
35
+ const colonIdx = body.lastIndexOf(':');
36
+ if (colonIdx === -1)
37
+ return null;
38
+ const name = body.slice(0, colonIdx);
39
+ const version = body.slice(colonIdx + 1);
40
+ if (!name || !version)
41
+ return null;
42
+ return { name, version };
43
+ }
44
+ /**
45
+ * Canonicalise SHACL bytes for the on-chain hash. The canonical form is:
46
+ * - UTF-8 normalised (callers are responsible for upstream NFC if needed)
47
+ * - keccak256 of the raw bytes
48
+ *
49
+ * This matches the on-chain `ShapeRegistry.defineShape(shapeHash)` expectation
50
+ * — both sides hash the exact same SHACL string.
51
+ */
52
+ export function shapeHash(shaclBytes) {
53
+ const bytes = typeof shaclBytes === 'string' ? utf8ToBytes(shaclBytes) : shaclBytes;
54
+ const digest = keccak_256(bytes);
55
+ let hex = '0x';
56
+ for (const v of digest) {
57
+ hex += v.toString(16).padStart(2, '0');
58
+ }
59
+ return hex;
60
+ }
61
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAIrD,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAqB,CAAC;AAEtD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,OAAe;IACzD,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,uDAAuD,IAAI,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,0DAA0D,OAAO,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,GAAG,gBAAgB,GAAG,IAAI,IAAI,OAAO,EAAE,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,QAAQ,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,UAA+B;IACvD,MAAM,KAAK,GAAG,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IACpF,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,GAAG,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,GAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * DOLCE+DnS Situation pattern — the substrate's typed base for every credential
3
+ * subject. Per spec 242 §5: substrate credentials describe a `Situation` with
4
+ * a `Description`, `Roles`, and `Participants`.
5
+ *
6
+ * Situation — the thing the credential is about (e.g. "this agreement",
7
+ * "this validation result", "this evidence anchor")
8
+ * Description — the typed shape spec the situation conforms to (SHACL IRI)
9
+ * Roles — typed slots filled by participants (e.g. issuer, holder,
10
+ * beneficiary, validator)
11
+ * Participants — the SAs filling each role
12
+ *
13
+ * Owning vocabularies define their specific Situation subclasses; this module
14
+ * exports the substrate base types every consumer composes against.
15
+ */
16
+ import type { Address } from '@agenticprimitives/types';
17
+ /** Ontology IRI of the Description shape (e.g. `apagr:AgreementCredential`). */
18
+ export type DescriptionRef = `${string}:${string}`;
19
+ /** Role identifier — local name within a Description. */
20
+ export type RoleName = string;
21
+ /** A typed Situation as a credential subject. The `[k: string]: unknown`
22
+ * index signature lets it satisfy `VerifiableCredential`'s `TSubject` constraint
23
+ * while keeping the typed `description / roles / body` fields tight. */
24
+ export interface Situation<TBody extends Record<string, unknown> = Record<string, unknown>> {
25
+ /** The Description shape the situation conforms to. */
26
+ description: DescriptionRef;
27
+ /** Typed slots — `{ roleName → AgentSA }`. */
28
+ roles: Record<RoleName, Address>;
29
+ /** Optional non-Agent participants (e.g. resource IRIs, document hashes). */
30
+ participants?: Record<string, string>;
31
+ /** The situation-specific payload. */
32
+ body: TBody;
33
+ /** Index signature so Situation satisfies VC's TSubject constraint. */
34
+ [key: string]: unknown;
35
+ }
36
+ /**
37
+ * Validate that a Situation declares the roles its Description requires.
38
+ * Used by SDK helpers before signing; production validation runs SHACL.
39
+ */
40
+ export declare function assertSituationRolesPresent(s: Situation, requiredRoles: RoleName[]): void;
41
+ /** Convenience constructor — builds the situation envelope from typed bits. */
42
+ export declare function buildSituation<TBody extends Record<string, unknown>>(args: {
43
+ description: DescriptionRef;
44
+ roles: Record<RoleName, Address>;
45
+ body: TBody;
46
+ participants?: Record<string, string>;
47
+ }): Situation<TBody>;
48
+ //# sourceMappingURL=situation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"situation.d.ts","sourceRoot":"","sources":["../src/situation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAExD,gFAAgF;AAChF,MAAM,MAAM,cAAc,GAAG,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;AAEnD,yDAAyD;AACzD,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B;;yEAEyE;AACzE,MAAM,WAAW,SAAS,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxF,uDAAuD;IACvD,WAAW,EAAE,cAAc,CAAC;IAC5B,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjC,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,sCAAsC;IACtC,IAAI,EAAE,KAAK,CAAC;IACZ,uEAAuE;IACvE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,IAAI,CAQzF;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE;IAC1E,WAAW,EAAE,cAAc,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,KAAK,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC,GAAG,SAAS,CAAC,KAAK,CAAC,CAOnB"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * DOLCE+DnS Situation pattern — the substrate's typed base for every credential
3
+ * subject. Per spec 242 §5: substrate credentials describe a `Situation` with
4
+ * a `Description`, `Roles`, and `Participants`.
5
+ *
6
+ * Situation — the thing the credential is about (e.g. "this agreement",
7
+ * "this validation result", "this evidence anchor")
8
+ * Description — the typed shape spec the situation conforms to (SHACL IRI)
9
+ * Roles — typed slots filled by participants (e.g. issuer, holder,
10
+ * beneficiary, validator)
11
+ * Participants — the SAs filling each role
12
+ *
13
+ * Owning vocabularies define their specific Situation subclasses; this module
14
+ * exports the substrate base types every consumer composes against.
15
+ */
16
+ /**
17
+ * Validate that a Situation declares the roles its Description requires.
18
+ * Used by SDK helpers before signing; production validation runs SHACL.
19
+ */
20
+ export function assertSituationRolesPresent(s, requiredRoles) {
21
+ const have = new Set(Object.keys(s.roles));
22
+ const missing = requiredRoles.filter((r) => !have.has(r));
23
+ if (missing.length > 0) {
24
+ throw new Error(`[verifiable-credentials] Situation '${s.description}' is missing required roles: ${missing.join(', ')}`);
25
+ }
26
+ }
27
+ /** Convenience constructor — builds the situation envelope from typed bits. */
28
+ export function buildSituation(args) {
29
+ return {
30
+ description: args.description,
31
+ roles: { ...args.roles },
32
+ participants: args.participants ? { ...args.participants } : undefined,
33
+ body: args.body,
34
+ };
35
+ }
36
+ //# sourceMappingURL=situation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"situation.js","sourceRoot":"","sources":["../src/situation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA0BH;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,CAAY,EAAE,aAAyB;IACjF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,uCAAuC,CAAC,CAAC,WAAW,gCAAgC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACzG,CAAC;IACJ,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAAwC,IAKrE;IACC,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,KAAK,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE;QACxB,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS;QACtE,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * W3C Verifiable Credentials 2.0 envelope types + `Eip712Signature2026` proof
3
+ * type. Substrate for all spine credential classes (Association, Evidence,
4
+ * Outcome, Validation, TrustUpdate, AgreementCredential, PaymentReceipt, ...).
5
+ *
6
+ * Authoritative spec: specs/242-trust-credentials-and-public-assertions.md §4.
7
+ * Architecture-of-record: ADR-0023 + ADR-0024 (composability table).
8
+ */
9
+ import type { Address, Hex } from '@agenticprimitives/types';
10
+ export type Hex32 = `0x${string}`;
11
+ export type ISODate = string;
12
+ /** W3C VC 2.0 default context. */
13
+ export declare const VC_CONTEXT_V2: "https://www.w3.org/ns/credentials/v2";
14
+ /** Substrate's Eip712Signature2026 context (proof-type alongside W3C VC). */
15
+ export declare const EIP712_SIG_2026_CONTEXT: "https://agenticprimitives.dev/contexts/eip712-signature-2026/v1";
16
+ /**
17
+ * Discriminator for the proof type. Primary in W1; BBS+ / SD-JWT reserved per
18
+ * PD-28 (privacy doc §2.3).
19
+ */
20
+ export type ProofType = 'Eip712Signature2026' | 'DataIntegrityProof' | 'SdJwtProof';
21
+ /**
22
+ * The primary W1 proof shape — EIP-712 typed-data signature verified via
23
+ * ERC-1271 against the issuer SA.
24
+ *
25
+ * Per ADR-0023:
26
+ * - `verificationMethod` SHOULD be a CAIP-10 reference to the issuer's SA.
27
+ * - `proofPurpose` is `assertionMethod` for issuer-attested credentials,
28
+ * `authentication` for holder-asserted ones.
29
+ */
30
+ export interface Eip712Signature2026Proof {
31
+ type: 'Eip712Signature2026';
32
+ created: ISODate;
33
+ verificationMethod: string;
34
+ proofPurpose: 'assertionMethod' | 'authentication' | 'capabilityInvocation';
35
+ /** Hex-encoded ERC-1271-verifiable signature. */
36
+ proofValue: Hex;
37
+ /** Optional EIP-712 domain hash for cross-stack reconciliation. */
38
+ eip712Domain?: {
39
+ name: string;
40
+ version: string;
41
+ chainId: number;
42
+ verifyingContract: Address;
43
+ };
44
+ /** Optional canonical-hash receipt of the credential body (RFC 8785 JCS). */
45
+ credentialHash?: Hex32;
46
+ }
47
+ /** Discriminated union for all supported proof types (W1: Eip712Signature2026 only). */
48
+ export type Proof = Eip712Signature2026Proof;
49
+ /** W3C VC StatusList2021 envelope (per `credentialStatus`). */
50
+ export interface CredentialStatus2021 {
51
+ id: string;
52
+ type: 'StatusList2021Entry' | 'RevocationList2020Status';
53
+ statusPurpose?: 'revocation' | 'suspension';
54
+ statusListIndex?: number;
55
+ statusListCredential?: string;
56
+ }
57
+ /**
58
+ * Per privacy doc D-42: every field MAY carry a per-field VisibilityTier
59
+ * override; consumers MAY render a partial VC by tier.
60
+ */
61
+ export type VisibilityTier = 'Public' | 'PublicCoarse' | 'PrivateCommitment' | 'PrivateZK' | 'OffchainOnly';
62
+ export interface DisclosurePolicy {
63
+ /** JSON-encoded { fieldPath → tier }. */
64
+ fieldDisclosure?: Record<string, VisibilityTier>;
65
+ /** Default tier applied to every unmapped field. */
66
+ defaultTier: VisibilityTier;
67
+ }
68
+ /**
69
+ * The canonical W3C VC 2.0 envelope, parameterised by the credential-subject
70
+ * shape. Implementations of substrate credential types (Association, Evidence,
71
+ * Outcome, Validation, TrustUpdate, AgreementCredential, PaymentReceipt) live
72
+ * in their owning packages; this envelope is substrate-wide.
73
+ */
74
+ export interface VerifiableCredential<TSubject extends Record<string, unknown> = Record<string, unknown>> {
75
+ '@context': readonly string[];
76
+ /** First element MUST be `'VerifiableCredential'`; subsequent are class names. */
77
+ type: readonly [...string[]];
78
+ /** CAIP-10 reference to the issuer SA (preferred), or a DID. */
79
+ issuer: string;
80
+ /** Issuance time. */
81
+ validFrom: ISODate;
82
+ /** Optional expiry. */
83
+ validUntil?: ISODate;
84
+ /** Credential subject — discriminated by class. */
85
+ credentialSubject: TSubject;
86
+ /** Optional revocation envelope (StatusList2021). */
87
+ credentialStatus?: CredentialStatus2021;
88
+ /** Optional schema pointer — `did:shape:<name>:<version>` (per PD-12 round-trip). */
89
+ credentialSchema?: {
90
+ id: string;
91
+ type: 'JsonSchema' | 'ShaclShape';
92
+ };
93
+ /** Substrate per-field DisclosurePolicy (D-42). */
94
+ disclosurePolicy?: DisclosurePolicy;
95
+ /** The proof (W1: Eip712Signature2026). */
96
+ proof?: Proof;
97
+ }
98
+ /** Convenience alias for a VC without a proof attached (pre-signing). */
99
+ export type UnsignedCredential<TSubject extends Record<string, unknown> = Record<string, unknown>> = Omit<VerifiableCredential<TSubject>, 'proof'>;
100
+ /**
101
+ * Standard EIP-712 domain for the substrate's `Eip712Signature2026` proof.
102
+ *
103
+ * Cross-stack typehash equality: any Solidity verifier MUST compute the same
104
+ * `typeHash` from the same primary type string + same field types. The
105
+ * canonical primary type is `VerifiableCredentialAttestation`:
106
+ *
107
+ * VerifiableCredentialAttestation(
108
+ * bytes32 credentialHash,
109
+ * string issuer,
110
+ * uint64 validFrom,
111
+ * uint64 validUntil,
112
+ * string proofPurpose
113
+ * )
114
+ */
115
+ export declare const VC_EIP712_TYPES: {
116
+ readonly VerifiableCredentialAttestation: readonly [{
117
+ readonly name: "credentialHash";
118
+ readonly type: "bytes32";
119
+ }, {
120
+ readonly name: "issuer";
121
+ readonly type: "string";
122
+ }, {
123
+ readonly name: "validFrom";
124
+ readonly type: "uint64";
125
+ }, {
126
+ readonly name: "validUntil";
127
+ readonly type: "uint64";
128
+ }, {
129
+ readonly name: "proofPurpose";
130
+ readonly type: "string";
131
+ }];
132
+ };
133
+ export declare const VC_DOMAIN_NAME: "AgenticPrimitivesVC";
134
+ export declare const VC_DOMAIN_VERSION: "1";
135
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * W3C Verifiable Credentials 2.0 envelope types + `Eip712Signature2026` proof
3
+ * type. Substrate for all spine credential classes (Association, Evidence,
4
+ * Outcome, Validation, TrustUpdate, AgreementCredential, PaymentReceipt, ...).
5
+ *
6
+ * Authoritative spec: specs/242-trust-credentials-and-public-assertions.md §4.
7
+ * Architecture-of-record: ADR-0023 + ADR-0024 (composability table).
8
+ */
9
+ /** W3C VC 2.0 default context. */
10
+ export const VC_CONTEXT_V2 = 'https://www.w3.org/ns/credentials/v2';
11
+ /** Substrate's Eip712Signature2026 context (proof-type alongside W3C VC). */
12
+ export const EIP712_SIG_2026_CONTEXT = 'https://agenticprimitives.dev/contexts/eip712-signature-2026/v1';
13
+ /**
14
+ * Standard EIP-712 domain for the substrate's `Eip712Signature2026` proof.
15
+ *
16
+ * Cross-stack typehash equality: any Solidity verifier MUST compute the same
17
+ * `typeHash` from the same primary type string + same field types. The
18
+ * canonical primary type is `VerifiableCredentialAttestation`:
19
+ *
20
+ * VerifiableCredentialAttestation(
21
+ * bytes32 credentialHash,
22
+ * string issuer,
23
+ * uint64 validFrom,
24
+ * uint64 validUntil,
25
+ * string proofPurpose
26
+ * )
27
+ */
28
+ export const VC_EIP712_TYPES = {
29
+ VerifiableCredentialAttestation: [
30
+ { name: 'credentialHash', type: 'bytes32' },
31
+ { name: 'issuer', type: 'string' },
32
+ { name: 'validFrom', type: 'uint64' },
33
+ { name: 'validUntil', type: 'uint64' },
34
+ { name: 'proofPurpose', type: 'string' },
35
+ ],
36
+ };
37
+ export const VC_DOMAIN_NAME = 'AgenticPrimitivesVC';
38
+ export const VC_DOMAIN_VERSION = '1';
39
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,kCAAkC;AAClC,MAAM,CAAC,MAAM,aAAa,GAAG,sCAA+C,CAAC;AAE7E,6EAA6E;AAC7E,MAAM,CAAC,MAAM,uBAAuB,GAClC,iEAA0E,CAAC;AAyG7E;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,+BAA+B,EAAE;QAC/B,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,SAAS,EAAE;QAC3C,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;QAClC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE;QACrC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE;QACtC,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE;KACzC;CACO,CAAC;AAEX,MAAM,CAAC,MAAM,cAAc,GAAG,qBAA8B,CAAC;AAC7D,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAY,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Verifier — checks that a VC's proof is valid.
3
+ *
4
+ * For W1 the verifier is structural + signature-shape only; the ERC-1271
5
+ * round-trip against the issuer SA on chain is delegated to consumers (who
6
+ * already hold a viem public client). The verifier returns enough information
7
+ * for the consumer to perform the on-chain check itself.
8
+ *
9
+ * Status-list resolution (StatusList2021) is likewise structural in W1 — we
10
+ * record whether a status entry was present + which list to fetch. Per
11
+ * ADR-0013 (no silent fallbacks) the consumer fetches the status list itself.
12
+ */
13
+ import type { Hex32, VerifiableCredential } from './types.js';
14
+ export interface VerificationResult {
15
+ /** Structural validity (envelope shape + canonical hash agreement). */
16
+ structural: boolean;
17
+ /** The digest the issuer SA's ERC-1271 path MUST validate. */
18
+ expectedDigest: Hex32 | null;
19
+ /** The proof value the consumer presents to `isValidSignatureNow`. */
20
+ proofValue: `0x${string}` | null;
21
+ /** The CAIP-10 issuer reference extracted from the verification method. */
22
+ issuerCaip10: string | null;
23
+ /** Status-list entry (if present); consumer fetches the list itself. */
24
+ statusListId: string | null;
25
+ /** Issues found — empty array if everything passes structural + canonical-hash checks. */
26
+ issues: string[];
27
+ }
28
+ /**
29
+ * Structural verification — does NOT make a network call. Returns the
30
+ * expected digest + proof value the caller MUST forward to the issuer SA's
31
+ * `isValidSignatureNow` (or other ERC-1271-aware path).
32
+ */
33
+ export declare function verifyCredentialStructural(vc: VerifiableCredential): VerificationResult;
34
+ //# sourceMappingURL=verifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../src/verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAEV,KAAK,EAEL,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,uEAAuE;IACvE,UAAU,EAAE,OAAO,CAAC;IACpB,8DAA8D;IAC9D,cAAc,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,sEAAsE;IACtE,UAAU,EAAE,KAAK,MAAM,EAAE,GAAG,IAAI,CAAC;IACjC,2EAA2E;IAC3E,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,wEAAwE;IACxE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,0FAA0F;IAC1F,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,oBAAoB,GAAG,kBAAkB,CAqFvF"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Verifier — checks that a VC's proof is valid.
3
+ *
4
+ * For W1 the verifier is structural + signature-shape only; the ERC-1271
5
+ * round-trip against the issuer SA on chain is delegated to consumers (who
6
+ * already hold a viem public client). The verifier returns enough information
7
+ * for the consumer to perform the on-chain check itself.
8
+ *
9
+ * Status-list resolution (StatusList2021) is likewise structural in W1 — we
10
+ * record whether a status entry was present + which list to fetch. Per
11
+ * ADR-0013 (no silent fallbacks) the consumer fetches the status list itself.
12
+ */
13
+ import { credentialHash, eip712Digest, isoToSeconds } from './proof.js';
14
+ /**
15
+ * Structural verification — does NOT make a network call. Returns the
16
+ * expected digest + proof value the caller MUST forward to the issuer SA's
17
+ * `isValidSignatureNow` (or other ERC-1271-aware path).
18
+ */
19
+ export function verifyCredentialStructural(vc) {
20
+ const issues = [];
21
+ if (!vc['@context'] || vc['@context'].length === 0) {
22
+ issues.push('missing @context');
23
+ }
24
+ if (!vc.type || vc.type[0] !== 'VerifiableCredential') {
25
+ issues.push('type[0] MUST be "VerifiableCredential"');
26
+ }
27
+ if (!vc.issuer)
28
+ issues.push('missing issuer');
29
+ if (!vc.validFrom)
30
+ issues.push('missing validFrom');
31
+ if (!vc.credentialSubject)
32
+ issues.push('missing credentialSubject');
33
+ if (vc.validUntil) {
34
+ const until = isoToSeconds(vc.validUntil);
35
+ const now = Math.floor(Date.now() / 1000);
36
+ if (until < now) {
37
+ issues.push(`credential expired at ${vc.validUntil}`);
38
+ }
39
+ }
40
+ if (!vc.proof) {
41
+ return {
42
+ structural: false,
43
+ expectedDigest: null,
44
+ proofValue: null,
45
+ issuerCaip10: null,
46
+ statusListId: vc.credentialStatus?.statusListCredential ?? null,
47
+ issues: [...issues, 'missing proof'],
48
+ };
49
+ }
50
+ if (vc.proof.type !== 'Eip712Signature2026') {
51
+ issues.push(`unsupported proof.type: ${vc.proof.type}`);
52
+ return {
53
+ structural: false,
54
+ expectedDigest: null,
55
+ proofValue: null,
56
+ issuerCaip10: null,
57
+ statusListId: vc.credentialStatus?.statusListCredential ?? null,
58
+ issues,
59
+ };
60
+ }
61
+ const proof = vc.proof;
62
+ if (!proof.eip712Domain) {
63
+ issues.push('Eip712Signature2026 proof MUST carry eip712Domain (for cross-stack verification)');
64
+ return {
65
+ structural: false,
66
+ expectedDigest: null,
67
+ proofValue: null,
68
+ issuerCaip10: null,
69
+ statusListId: vc.credentialStatus?.statusListCredential ?? null,
70
+ issues,
71
+ };
72
+ }
73
+ const bodyHash = credentialHash(vc);
74
+ if (proof.credentialHash && proof.credentialHash !== bodyHash) {
75
+ issues.push(`proof.credentialHash (${proof.credentialHash}) does not match canonical hash of credential body (${bodyHash})`);
76
+ }
77
+ const expectedDigest = eip712Digest({
78
+ credentialBodyHash: bodyHash,
79
+ issuer: vc.issuer,
80
+ validFrom: isoToSeconds(vc.validFrom),
81
+ validUntil: isoToSeconds(vc.validUntil),
82
+ proofPurpose: proof.proofPurpose,
83
+ chainId: proof.eip712Domain.chainId,
84
+ verifyingContract: proof.eip712Domain.verifyingContract,
85
+ });
86
+ const issuerCaip10 = parseCaip10IssuerFromVerificationMethod(proof.verificationMethod);
87
+ return {
88
+ structural: issues.length === 0,
89
+ expectedDigest,
90
+ proofValue: proof.proofValue,
91
+ issuerCaip10,
92
+ statusListId: vc.credentialStatus?.statusListCredential ?? null,
93
+ issues,
94
+ };
95
+ }
96
+ function parseCaip10IssuerFromVerificationMethod(method) {
97
+ // Format: `eip155:<chainId>:<address>#<keyName>`
98
+ const hashIdx = method.indexOf('#');
99
+ if (hashIdx === -1)
100
+ return null;
101
+ const ref = method.slice(0, hashIdx);
102
+ // Light sanity check
103
+ if (!/^eip155:\d+:0x[0-9a-fA-F]+$/.test(ref))
104
+ return null;
105
+ return ref;
106
+ }
107
+ //# sourceMappingURL=verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.js","sourceRoot":"","sources":["../src/verifier.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@agenticprimitives/verifiable-credentials",
3
+ "version": "0.0.0-alpha.2",
4
+ "description": "W3C Verifiable Credentials envelope + Eip712Signature2026 proof + DOLCE+DnS Situation bases + ontology-shape schema registration. Substrate for layers 12–15 credential types.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/agentictrustlabs/agenticprimitives.git",
9
+ "directory": "packages/verifiable-credentials"
10
+ },
11
+ "homepage": "https://github.com/agentictrustlabs/agenticprimitives/tree/master/packages/verifiable-credentials",
12
+ "bugs": {
13
+ "url": "https://github.com/agentictrustlabs/agenticprimitives/issues"
14
+ },
15
+ "type": "module",
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ }
23
+ },
24
+ "files": [
25
+ "LICENSE",
26
+ "dist",
27
+ "spec.md",
28
+ "README.md"
29
+ ],
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "peerDependencies": {
34
+ "viem": "^2.52.2",
35
+ "@agenticprimitives/types": "1.0.0-alpha.6",
36
+ "@agenticprimitives/ontology": "1.0.0-alpha.6"
37
+ },
38
+ "dependencies": {
39
+ "@noble/hashes": "^2.2.0"
40
+ },
41
+ "devDependencies": {
42
+ "vitest": "^4.1.8",
43
+ "viem": "^2.52.2"
44
+ },
45
+ "keywords": [
46
+ "agentic",
47
+ "primitives",
48
+ "verifiable-credentials"
49
+ ],
50
+ "scripts": {
51
+ "build": "tsc -p tsconfig.build.json",
52
+ "typecheck": "tsc -p tsconfig.json --noEmit",
53
+ "test": "vitest run --passWithNoTests",
54
+ "test:unit": "vitest run test/unit --passWithNoTests",
55
+ "test:watch": "vitest",
56
+ "clean": "rm -rf dist"
57
+ }
58
+ }
package/spec.md ADDED
@@ -0,0 +1,5 @@
1
+ # Spec pointer
2
+
3
+ Canonical spec: [`../../specs/242-*.md`](../../specs/)
4
+
5
+ Owning layers (per [coordination-substrate.md](../../docs/architecture/coordination-substrate.md)): envelope.