@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 +21 -0
- package/README.md +20 -0
- package/dist/canonical.d.ts +34 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +146 -0
- package/dist/canonical.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/proof.d.ts +59 -0
- package/dist/proof.d.ts.map +1 -0
- package/dist/proof.js +105 -0
- package/dist/proof.js.map +1 -0
- package/dist/schema.d.ts +35 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +61 -0
- package/dist/schema.js.map +1 -0
- package/dist/situation.d.ts +48 -0
- package/dist/situation.d.ts.map +1 -0
- package/dist/situation.js +36 -0
- package/dist/situation.js.map +1 -0
- package/dist/types.d.ts +135 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +39 -0
- package/dist/types.js.map +1 -0
- package/dist/verifier.d.ts +34 -0
- package/dist/verifier.d.ts.map +1 -0
- package/dist/verifier.js +107 -0
- package/dist/verifier.js.map +1 -0
- package/package.json +58 -0
- package/spec.md +5 -0
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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/proof.d.ts
ADDED
|
@@ -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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"}
|
package/dist/schema.d.ts
ADDED
|
@@ -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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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"}
|
package/dist/verifier.js
ADDED
|
@@ -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
|
+
}
|