@agenticprimitives/verifiable-credentials 0.0.0-alpha.2 → 0.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -6
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/verifier.d.ts +47 -8
- package/dist/verifier.d.ts.map +1 -1
- package/dist/verifier.js +80 -9
- package/dist/verifier.js.map +1 -1
- package/package.json +14 -14
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -1,15 +1,40 @@
|
|
|
1
1
|
# @agenticprimitives/verifiable-credentials
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**A credential is only as durable as the identity it points at.** Most verifiable-credential stacks bind claims to a key — and when the key rotates, the trust graph quietly breaks. Here the issuer and subject of every credential is a Smart Agent address: a persistent ERC-4337 account whose keys are replaceable facets. Rotate a passkey, recover from a lost device, swap a signer — the address persists, and every credential issued by or about it stays verifiable.
|
|
4
4
|
|
|
5
|
-
W3C
|
|
5
|
+
This package is the W3C VC 2.0 envelope for that model: an `Eip712Signature2026` proof signed by a smart account and verified with an ERC-1271 round-trip against the chain, plus the RFC 8785 (JCS) canonical hash that every downstream registry stores as the on-chain anchor. It is the substrate layer — specific credential types (associations, agreements, evidence, outcomes, receipts) are composed on top by consumer packages.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
**Authoritative spec:** [`specs/242-*.md`](../../specs/) — see `spec.md` for the symlink to the canonical spec.
|
|
7
|
+
> Part of [agenticprimitives](../../README.md) — the trust substrate for the agent economy: one canonical Smart Agent identity with custody, delegation, naming, credentials, and audit evidence designed as one system.
|
|
9
8
|
|
|
10
|
-
## What
|
|
9
|
+
## What ships today
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
- **W3C VC 2.0 envelope** — `@context`, `type`, `issuer`, `validFrom`, `credentialSubject`, `proof`, `credentialStatus` (`VerifiableCredential`, `UnsignedCredential` types).
|
|
12
|
+
- **`Eip712Signature2026` proof** — `signCredential(unsigned, signer)` produces the proof; `eip712Digest(...)` matches the Solidity verifier byte-for-byte (cross-stack typehash equality, CI-gated per spec 242 §4.3).
|
|
13
|
+
- **Verifier** — `verifyCredential(vc, client)` runs structural checks, recomputes the digest, and verifies the issuer signature via ERC-1271 against the issuer's Smart Agent. One mechanism, no silent fallbacks ([ADR-0013](../../docs/architecture/decisions/0013-no-silent-fallbacks.md)). `verifyCredentialStructural(vc)` is the offline subset.
|
|
14
|
+
- **Canonical hash** — `credentialHash(vc)` / `canonicalHash(...)` / `jcsCanonicalize(...)`: the RFC 8785 JCS hash used as the credential anchor everywhere downstream (attestation registries, vault indexes, status lists).
|
|
15
|
+
- **DOLCE+DnS Situation pattern** — `buildSituation(...)` and the `Situation` / `DescriptionRef` / `RoleName` shapes that all substrate credential subjects compose against.
|
|
16
|
+
- **Schema URIs** — `buildShapeUri` / `parseShapeUri` / `shapeHash` for the `did:shape:<name>:<version>` convention that pairs with the on-chain `ShapeRegistry`.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { credentialHash, verifyCredential } from '@agenticprimitives/verifiable-credentials';
|
|
20
|
+
|
|
21
|
+
const anchor = credentialHash(vc); // RFC 8785 JCS hash — what registries store
|
|
22
|
+
const result = await verifyCredential(vc, client); // ERC-1271 round-trip against the issuer Smart Agent
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## How it's different
|
|
26
|
+
|
|
27
|
+
Veramo, Trinsic, and the broader W3C VC tooling ecosystem resolve issuers through DID methods and key registries — so credential validity is coupled to key material. Here the issuer is a CAIP-10 smart-account address and verification is ERC-1271 against the chain: **keys rotate, the address persists, credentials survive recovery** ([ADR-0011](../../docs/architecture/decisions/0011-credential-recovery-and-re-association.md)). And because the EIP-712 digest is locked to its Solidity counterpart by a CI gate, the contracts and the SDK are one artifact — the client cannot drift from the chain, which is precisely where stitched VC stacks decay.
|
|
28
|
+
|
|
29
|
+
The package is deliberately a leaf: it imports only `types`, `ontology`, `viem`, and `@noble/hashes`, and defines no specific credential types — `attestations`, `agreements`, `fulfillment`, and `payments` own those.
|
|
30
|
+
|
|
31
|
+
## Status
|
|
32
|
+
|
|
33
|
+
**W1 foundational — implemented and security-load-bearing.** The envelope, proof, canonical hash, and verifier ship today and are exercised by downstream packages; verifier findings VC-1/VC-2 are closed (see [AUDIT.md](./AUDIT.md)). Alternative proof types (BBS+ / SD-JWT / AnonCreds) have a reserved envelope slot and land in later waves per the [W1 implementation wave plan](../../docs/architecture/w1-implementation-wave-plan.md).
|
|
34
|
+
|
|
35
|
+
> Testnet/pilot-ready. Production launch is gated on the public checklist in the root README — including third-party contract audit and governance key rotation. Track every security finding live in [`docs/audits/findings.yaml`](../../docs/audits/findings.yaml).
|
|
36
|
+
|
|
37
|
+
**Authoritative spec:** [`specs/242-trust-credentials-and-public-assertions.md`](../../specs/242-trust-credentials-and-public-assertions.md) §4 — see `spec.md` for the symlink. Bounded surface: `CLAUDE.md` + `capability.manifest.json`.
|
|
13
38
|
|
|
14
39
|
## Build
|
|
15
40
|
|
package/dist/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export { assertSituationRolesPresent, buildSituation, } from './situation.js';
|
|
|
18
18
|
export type { Situation, DescriptionRef, RoleName } from './situation.js';
|
|
19
19
|
export { credentialHash, eip712Digest, isoToSeconds, signCredential, viemSignerFromWallet, } from './proof.js';
|
|
20
20
|
export type { CredentialSigner } from './proof.js';
|
|
21
|
-
export { verifyCredentialStructural } from './verifier.js';
|
|
22
|
-
export type { VerificationResult } from './verifier.js';
|
|
21
|
+
export { verifyCredential, verifyCredentialStructural, parseEip155Caip10 } from './verifier.js';
|
|
22
|
+
export type { VerificationResult, VerifyCredentialResult, Erc1271Verifier, Caip10Eip155, } from './verifier.js';
|
|
23
23
|
export { SHAPE_DID_PREFIX, buildShapeUri, parseShapeUri, shapeHash } from './schema.js';
|
|
24
24
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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,gBAAgB,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAChG,YAAY,EACV,kBAAkB,EAClB,sBAAsB,EACtB,eAAe,EACf,YAAY,GACb,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ export { assertSituationRolesPresent, buildSituation, } from './situation.js';
|
|
|
20
20
|
// Proof builder
|
|
21
21
|
export { credentialHash, eip712Digest, isoToSeconds, signCredential, viemSignerFromWallet, } from './proof.js';
|
|
22
22
|
// Verifier
|
|
23
|
-
export { verifyCredentialStructural } from './verifier.js';
|
|
23
|
+
export { verifyCredential, verifyCredentialStructural, parseEip155Caip10 } from './verifier.js';
|
|
24
24
|
// Schema registration
|
|
25
25
|
export { SHAPE_DID_PREFIX, buildShapeUri, parseShapeUri, shapeHash } from './schema.js';
|
|
26
26
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;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;
|
|
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,gBAAgB,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAQhG,sBAAsB;AACtB,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/verifier.d.ts
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Verifier — checks that a VC's proof is valid.
|
|
2
|
+
* Verifier — checks that a VC's proof is valid (findings VC-1 / VC-2, closed).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* `verifyCredential(vc, publicClient)` performs the ERC-1271 round-trip against
|
|
5
|
+
* the issuer SA on chain and FAILS CLOSED — `credentialHash` is mandatory, and
|
|
6
|
+
* the EIP-712 digest pins `verifyingContract` to the issuer SA + binds `chainId`,
|
|
7
|
+
* so an attacker can't substitute a different verifying domain. The structural
|
|
8
|
+
* helpers remain for callers that only need shape validation, but the authority
|
|
9
|
+
* check is `verifyCredential`; there is no fallback path (ADR-0013).
|
|
8
10
|
*
|
|
9
|
-
* Status-list resolution (StatusList2021)
|
|
10
|
-
*
|
|
11
|
-
* ADR-0013
|
|
11
|
+
* Status-list resolution (StatusList2021): the verifier records whether a status
|
|
12
|
+
* entry was present + which list to fetch; the consumer fetches it (no silent
|
|
13
|
+
* fallback, ADR-0013).
|
|
12
14
|
*/
|
|
13
15
|
import type { Hex32, VerifiableCredential } from './types.js';
|
|
16
|
+
/** Parsed `eip155:<chainId>:<address>` CAIP-10 reference. */
|
|
17
|
+
export interface Caip10Eip155 {
|
|
18
|
+
chainId: number;
|
|
19
|
+
address: `0x${string}`;
|
|
20
|
+
}
|
|
21
|
+
/** Parse an `eip155:<chainId>:0x…40` CAIP-10 account id, or null. Both `vc.issuer` and the
|
|
22
|
+
* `verificationMethod` prefix use this form — the VC-2 domain-binding source of truth. */
|
|
23
|
+
export declare function parseEip155Caip10(ref: string): Caip10Eip155 | null;
|
|
14
24
|
export interface VerificationResult {
|
|
15
25
|
/** Structural validity (envelope shape + canonical hash agreement). */
|
|
16
26
|
structural: boolean;
|
|
@@ -31,4 +41,33 @@ export interface VerificationResult {
|
|
|
31
41
|
* `isValidSignatureNow` (or other ERC-1271-aware path).
|
|
32
42
|
*/
|
|
33
43
|
export declare function verifyCredentialStructural(vc: VerifiableCredential): VerificationResult;
|
|
44
|
+
/** Minimal ERC-1271 verifier seam — satisfied structurally by a viem `PublicClient`
|
|
45
|
+
* (`client.verifyHash({ address, hash, signature })`). Kept structural so the package stays a
|
|
46
|
+
* graph leaf and isn't pinned to a single viem version. */
|
|
47
|
+
export interface Erc1271Verifier {
|
|
48
|
+
verifyHash(args: {
|
|
49
|
+
address: `0x${string}`;
|
|
50
|
+
hash: `0x${string}`;
|
|
51
|
+
signature: `0x${string}`;
|
|
52
|
+
}): Promise<boolean>;
|
|
53
|
+
}
|
|
54
|
+
export interface VerifyCredentialResult {
|
|
55
|
+
/** True ONLY when the structural checks pass AND the issuer SA's ERC-1271 path validates the
|
|
56
|
+
* signature over the expected digest. Fail-closed: any error/anomaly → false. */
|
|
57
|
+
valid: boolean;
|
|
58
|
+
/** The structural sub-result (digest, proof value, issuer ref, issues). */
|
|
59
|
+
structuralResult: VerificationResult;
|
|
60
|
+
/** All issues — structural plus signature/verification failures. */
|
|
61
|
+
issues: string[];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Full credential verification (VC-1): structural checks PLUS the on-chain ERC-1271 round-trip
|
|
65
|
+
* against the issuer SA resolved from `vc.issuer`. This is the function consumers (content
|
|
66
|
+
* entitlements, agent-skills, geo-features, related-agents) MUST gate on — `verifyCredentialStructural`
|
|
67
|
+
* alone proves nothing about the signature.
|
|
68
|
+
*
|
|
69
|
+
* Fail-closed per ADR-0013: a structural failure, an unresolvable issuer, a verification-call error,
|
|
70
|
+
* or a non-validating signature all return `valid: false` — never a silent accept.
|
|
71
|
+
*/
|
|
72
|
+
export declare function verifyCredential(vc: VerifiableCredential, client: Erc1271Verifier): Promise<VerifyCredentialResult>;
|
|
34
73
|
//# sourceMappingURL=verifier.d.ts.map
|
package/dist/verifier.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../src/verifier.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../src/verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAEV,KAAK,EAEL,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAEpB,6DAA6D;AAC7D,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;CACxB;AAED;2FAC2F;AAC3F,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAIlE;AAED,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,CAmHvF;AAYD;;4DAE4D;AAC5D,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,IAAI,EAAE;QACf,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;QACvB,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC;QACpB,SAAS,EAAE,KAAK,MAAM,EAAE,CAAC;KAC1B,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC;sFACkF;IAClF,KAAK,EAAE,OAAO,CAAC;IACf,2EAA2E;IAC3E,gBAAgB,EAAE,kBAAkB,CAAC;IACrC,oEAAoE;IACpE,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,oBAAoB,EACxB,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,sBAAsB,CAAC,CAwBjC"}
|
package/dist/verifier.js
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Verifier — checks that a VC's proof is valid.
|
|
2
|
+
* Verifier — checks that a VC's proof is valid (findings VC-1 / VC-2, closed).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* `verifyCredential(vc, publicClient)` performs the ERC-1271 round-trip against
|
|
5
|
+
* the issuer SA on chain and FAILS CLOSED — `credentialHash` is mandatory, and
|
|
6
|
+
* the EIP-712 digest pins `verifyingContract` to the issuer SA + binds `chainId`,
|
|
7
|
+
* so an attacker can't substitute a different verifying domain. The structural
|
|
8
|
+
* helpers remain for callers that only need shape validation, but the authority
|
|
9
|
+
* check is `verifyCredential`; there is no fallback path (ADR-0013).
|
|
8
10
|
*
|
|
9
|
-
* Status-list resolution (StatusList2021)
|
|
10
|
-
*
|
|
11
|
-
* ADR-0013
|
|
11
|
+
* Status-list resolution (StatusList2021): the verifier records whether a status
|
|
12
|
+
* entry was present + which list to fetch; the consumer fetches it (no silent
|
|
13
|
+
* fallback, ADR-0013).
|
|
12
14
|
*/
|
|
13
15
|
import { credentialHash, eip712Digest, isoToSeconds } from './proof.js';
|
|
16
|
+
/** Parse an `eip155:<chainId>:0x…40` CAIP-10 account id, or null. Both `vc.issuer` and the
|
|
17
|
+
* `verificationMethod` prefix use this form — the VC-2 domain-binding source of truth. */
|
|
18
|
+
export function parseEip155Caip10(ref) {
|
|
19
|
+
const m = /^eip155:(\d+):(0x[0-9a-fA-F]{40})$/.exec(ref);
|
|
20
|
+
if (!m)
|
|
21
|
+
return null;
|
|
22
|
+
return { chainId: Number(m[1]), address: m[2] };
|
|
23
|
+
}
|
|
14
24
|
/**
|
|
15
25
|
* Structural verification — does NOT make a network call. Returns the
|
|
16
26
|
* expected digest + proof value the caller MUST forward to the issuer SA's
|
|
@@ -71,9 +81,34 @@ export function verifyCredentialStructural(vc) {
|
|
|
71
81
|
};
|
|
72
82
|
}
|
|
73
83
|
const bodyHash = credentialHash(vc);
|
|
74
|
-
|
|
84
|
+
// VC-1: `credentialHash` is MANDATORY — a forger must not be able to drop it to skip the
|
|
85
|
+
// body-integrity check. Missing OR mismatched is a structural failure.
|
|
86
|
+
if (!proof.credentialHash) {
|
|
87
|
+
issues.push('proof.credentialHash is required (binds the proof to the canonical credential body)');
|
|
88
|
+
}
|
|
89
|
+
else if (proof.credentialHash !== bodyHash) {
|
|
75
90
|
issues.push(`proof.credentialHash (${proof.credentialHash}) does not match canonical hash of credential body (${bodyHash})`);
|
|
76
91
|
}
|
|
92
|
+
// VC-2: the EIP-712 domain is attacker-supplied inside the proof. Bind it to the credential's
|
|
93
|
+
// declared `issuer` SA — the digest is meaningless if it can be computed against a contract /
|
|
94
|
+
// chain the attacker controls. `verifyingContract` MUST equal the issuer SA, `chainId` MUST equal
|
|
95
|
+
// the issuer's chain, and the `verificationMethod` address MUST resolve to the same SA.
|
|
96
|
+
const issuerAcct = parseEip155Caip10(vc.issuer);
|
|
97
|
+
if (!issuerAcct) {
|
|
98
|
+
issues.push(`vc.issuer is not a verifiable eip155 CAIP-10 account id: ${vc.issuer}`);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
if (proof.eip712Domain.verifyingContract.toLowerCase() !== issuerAcct.address.toLowerCase()) {
|
|
102
|
+
issues.push(`proof.eip712Domain.verifyingContract (${proof.eip712Domain.verifyingContract}) MUST equal the issuer SA (${issuerAcct.address})`);
|
|
103
|
+
}
|
|
104
|
+
if (proof.eip712Domain.chainId !== issuerAcct.chainId) {
|
|
105
|
+
issues.push(`proof.eip712Domain.chainId (${proof.eip712Domain.chainId}) MUST equal the issuer chainId (${issuerAcct.chainId})`);
|
|
106
|
+
}
|
|
107
|
+
const vmAcct = parseEip155Caip10(proof.verificationMethod.split('#')[0] ?? '');
|
|
108
|
+
if (!vmAcct || vmAcct.address.toLowerCase() !== issuerAcct.address.toLowerCase()) {
|
|
109
|
+
issues.push(`proof.verificationMethod (${proof.verificationMethod}) MUST resolve to the issuer SA (${issuerAcct.address})`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
77
112
|
const expectedDigest = eip712Digest({
|
|
78
113
|
credentialBodyHash: bodyHash,
|
|
79
114
|
issuer: vc.issuer,
|
|
@@ -104,4 +139,40 @@ function parseCaip10IssuerFromVerificationMethod(method) {
|
|
|
104
139
|
return null;
|
|
105
140
|
return ref;
|
|
106
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Full credential verification (VC-1): structural checks PLUS the on-chain ERC-1271 round-trip
|
|
144
|
+
* against the issuer SA resolved from `vc.issuer`. This is the function consumers (content
|
|
145
|
+
* entitlements, agent-skills, geo-features, related-agents) MUST gate on — `verifyCredentialStructural`
|
|
146
|
+
* alone proves nothing about the signature.
|
|
147
|
+
*
|
|
148
|
+
* Fail-closed per ADR-0013: a structural failure, an unresolvable issuer, a verification-call error,
|
|
149
|
+
* or a non-validating signature all return `valid: false` — never a silent accept.
|
|
150
|
+
*/
|
|
151
|
+
export async function verifyCredential(vc, client) {
|
|
152
|
+
const structuralResult = verifyCredentialStructural(vc);
|
|
153
|
+
const issues = [...structuralResult.issues];
|
|
154
|
+
if (!structuralResult.structural || !structuralResult.expectedDigest || !structuralResult.proofValue) {
|
|
155
|
+
return { valid: false, structuralResult, issues };
|
|
156
|
+
}
|
|
157
|
+
const issuerAcct = parseEip155Caip10(vc.issuer);
|
|
158
|
+
if (!issuerAcct) {
|
|
159
|
+
issues.push('cannot resolve issuer SA for ERC-1271 verification');
|
|
160
|
+
return { valid: false, structuralResult, issues };
|
|
161
|
+
}
|
|
162
|
+
let ok;
|
|
163
|
+
try {
|
|
164
|
+
ok = await client.verifyHash({
|
|
165
|
+
address: issuerAcct.address,
|
|
166
|
+
hash: structuralResult.expectedDigest,
|
|
167
|
+
signature: structuralResult.proofValue,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
issues.push(`ERC-1271 verification call failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
172
|
+
return { valid: false, structuralResult, issues };
|
|
173
|
+
}
|
|
174
|
+
if (!ok)
|
|
175
|
+
issues.push('issuer ERC-1271 signature did not validate over the expected digest');
|
|
176
|
+
return { valid: ok, structuralResult, issues };
|
|
177
|
+
}
|
|
107
178
|
//# sourceMappingURL=verifier.js.map
|
package/dist/verifier.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verifier.js","sourceRoot":"","sources":["../src/verifier.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"verifier.js","sourceRoot":"","sources":["../src/verifier.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticprimitives/verifiable-credentials",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.3",
|
|
4
4
|
"description": "W3C Verifiable Credentials envelope + Eip712Signature2026 proof + DOLCE+DnS Situation bases + ontology-shape schema registration. Substrate for layers 12–15 credential types.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -27,13 +27,21 @@
|
|
|
27
27
|
"spec.md",
|
|
28
28
|
"README.md"
|
|
29
29
|
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc -p tsconfig.build.json",
|
|
32
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"test:unit": "vitest run test/unit --passWithNoTests",
|
|
35
|
+
"test:watch": "vitest",
|
|
36
|
+
"clean": "rm -rf dist"
|
|
37
|
+
},
|
|
30
38
|
"publishConfig": {
|
|
31
39
|
"access": "public"
|
|
32
40
|
},
|
|
33
41
|
"peerDependencies": {
|
|
34
|
-
"
|
|
35
|
-
"@agenticprimitives/
|
|
36
|
-
"
|
|
42
|
+
"@agenticprimitives/types": "workspace:*",
|
|
43
|
+
"@agenticprimitives/ontology": "workspace:*",
|
|
44
|
+
"viem": "^2.52.2"
|
|
37
45
|
},
|
|
38
46
|
"dependencies": {
|
|
39
47
|
"@noble/hashes": "^2.2.0"
|
|
@@ -46,13 +54,5 @@
|
|
|
46
54
|
"agentic",
|
|
47
55
|
"primitives",
|
|
48
56
|
"verifiable-credentials"
|
|
49
|
-
]
|
|
50
|
-
|
|
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
|
-
}
|
|
57
|
+
]
|
|
58
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
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.
|