@solidus-network/sdk 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chain/bbs.d.ts +128 -0
- package/dist/chain/bbs.d.ts.map +1 -0
- package/dist/chain/bbs.js +142 -0
- package/dist/chain/bbs.js.map +1 -0
- package/dist/chain/credentials.js +6 -6
- package/dist/chain/credentials.js.map +1 -1
- package/dist/chain/did.d.ts +52 -0
- package/dist/chain/did.d.ts.map +1 -1
- package/dist/chain/did.js +91 -2
- package/dist/chain/did.js.map +1 -1
- package/dist/chain/index.d.ts.map +1 -1
- package/dist/chain/index.js +2 -0
- package/dist/chain/index.js.map +1 -1
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/sdjwt/index.d.ts +8 -0
- package/dist/sdjwt/index.d.ts.map +1 -0
- package/dist/sdjwt/index.js +8 -0
- package/dist/sdjwt/index.js.map +1 -0
- package/dist/sdjwt/issue.d.ts +12 -0
- package/dist/sdjwt/issue.d.ts.map +1 -0
- package/dist/sdjwt/issue.js +119 -0
- package/dist/sdjwt/issue.js.map +1 -0
- package/dist/sdjwt/present.d.ts +15 -0
- package/dist/sdjwt/present.d.ts.map +1 -0
- package/dist/sdjwt/present.js +80 -0
- package/dist/sdjwt/present.js.map +1 -0
- package/dist/sdjwt/signer.d.ts +59 -0
- package/dist/sdjwt/signer.d.ts.map +1 -0
- package/dist/sdjwt/signer.js +119 -0
- package/dist/sdjwt/signer.js.map +1 -0
- package/dist/sdjwt/status-list.d.ts +61 -0
- package/dist/sdjwt/status-list.d.ts.map +1 -0
- package/dist/sdjwt/status-list.js +63 -0
- package/dist/sdjwt/status-list.js.map +1 -0
- package/dist/sdjwt/types.d.ts +181 -0
- package/dist/sdjwt/types.d.ts.map +1 -0
- package/dist/sdjwt/types.js +12 -0
- package/dist/sdjwt/types.js.map +1 -0
- package/dist/sdjwt/verify.d.ts +23 -0
- package/dist/sdjwt/verify.d.ts.map +1 -0
- package/dist/sdjwt/verify.js +201 -0
- package/dist/sdjwt/verify.js.map +1 -0
- package/dist/stub/credentials.js +3 -3
- package/dist/stub/credentials.js.map +1 -1
- package/package.json +7 -5
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status list (draft-ietf-oauth-status-list) helper for issuers.
|
|
3
|
+
*
|
|
4
|
+
* The lifecycle:
|
|
5
|
+
* 1. Issuer creates a `StatusList` (a bitstring of N statuses,
|
|
6
|
+
* typically 1 bit per credential — 0 = active, 1 = revoked).
|
|
7
|
+
* 2. Issuer wraps it in a JWT signed by the issuer's key, served at
|
|
8
|
+
* a stable URL (e.g., `/status-lists/<id>`).
|
|
9
|
+
* 3. Each issued SD-JWT VC carries a `status.status_list.{uri, idx}`
|
|
10
|
+
* pointing at one bit in the list.
|
|
11
|
+
* 4. To revoke a credential, the issuer flips its bit and republishes
|
|
12
|
+
* the (now-updated) JWT at the same URL.
|
|
13
|
+
* 5. Verifiers refetch the list (cache-respecting) and check the bit.
|
|
14
|
+
*
|
|
15
|
+
* `createStatusListJwt` is a thin wrapper around `@sd-jwt/jwt-status-list`
|
|
16
|
+
* that uses Ed25519 / EdDSA to match the rest of Solidus's signing
|
|
17
|
+
* conventions.
|
|
18
|
+
*/
|
|
19
|
+
import * as ed from '@noble/ed25519';
|
|
20
|
+
import { StatusList, createHeaderAndPayload, } from '@sd-jwt/jwt-status-list';
|
|
21
|
+
function toBase64Url(bytes) {
|
|
22
|
+
return Buffer.from(bytes)
|
|
23
|
+
.toString('base64')
|
|
24
|
+
.replace(/\+/g, '-')
|
|
25
|
+
.replace(/\//g, '_')
|
|
26
|
+
.replace(/=/g, '');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build a signed status-list JWT.
|
|
30
|
+
*
|
|
31
|
+
* Returns the JWT in compact form. Issuers serve this at the URL
|
|
32
|
+
* embedded in their issued SD-JWT VCs' `status.status_list.uri` claim.
|
|
33
|
+
*/
|
|
34
|
+
export async function createStatusListJwt(params) {
|
|
35
|
+
if (params.issuerPrivateKey.length !== 32) {
|
|
36
|
+
throw new Error(`issuerPrivateKey must be 32 bytes, got ${params.issuerPrivateKey.length}`);
|
|
37
|
+
}
|
|
38
|
+
const bitsPerStatus = params.bitsPerStatus ?? 1;
|
|
39
|
+
const list = new StatusList(new Array(params.totalStatuses).fill(0), bitsPerStatus);
|
|
40
|
+
for (const entry of params.revoked ?? []) {
|
|
41
|
+
if (typeof entry === 'number') {
|
|
42
|
+
list.setStatus(entry, 1);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
list.setStatus(entry[0], entry[1]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const now = Math.floor(Date.now() / 1000);
|
|
49
|
+
const basePayload = {
|
|
50
|
+
iss: params.issuer,
|
|
51
|
+
sub: params.uri,
|
|
52
|
+
iat: now,
|
|
53
|
+
};
|
|
54
|
+
if (params.ttlSeconds !== undefined)
|
|
55
|
+
basePayload['ttl'] = params.ttlSeconds;
|
|
56
|
+
const { header, payload } = createHeaderAndPayload(list, basePayload, { alg: 'EdDSA', typ: 'statuslist+jwt' });
|
|
57
|
+
const headerSegment = toBase64Url(new TextEncoder().encode(JSON.stringify(header)));
|
|
58
|
+
const payloadSegment = toBase64Url(new TextEncoder().encode(JSON.stringify(payload)));
|
|
59
|
+
const signingInput = `${headerSegment}.${payloadSegment}`;
|
|
60
|
+
const signature = await ed.signAsync(new TextEncoder().encode(signingInput), params.issuerPrivateKey);
|
|
61
|
+
return `${signingInput}.${toBase64Url(signature)}`;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=status-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-list.js","sourceRoot":"","sources":["../../src/sdjwt/status-list.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACpC,OAAO,EACL,UAAU,EACV,sBAAsB,GAEvB,MAAM,yBAAyB,CAAA;AAEhC,SAAS,WAAW,CAAC,KAAiB;IACpC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;SACtB,QAAQ,CAAC,QAAQ,CAAC;SAClB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;AACtB,CAAC;AA2CD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAiC;IAEjC,IAAI,MAAM,CAAC,gBAAgB,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,0CAA0C,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAC3E,CAAA;IACH,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,CAAC,CAAA;IAC/C,MAAM,IAAI,GAAG,IAAI,UAAU,CACzB,IAAI,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EACvC,aAAa,CACd,CAAA;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QACzC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QAC1B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QACpC,CAAC;IACH,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;IACzC,MAAM,WAAW,GAA4B;QAC3C,GAAG,EAAE,MAAM,CAAC,MAAM;QAClB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,GAAG,EAAE,GAAG;KACT,CAAA;IACD,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS;QAAE,WAAW,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,UAAU,CAAA;IAE3E,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,sBAAsB,CAChD,IAAI,EACJ,WAAoB,EACpB,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,gBAAgB,EAAE,CACxC,CAAA;IAED,MAAM,aAAa,GAAG,WAAW,CAC/B,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CACjD,CAAA;IACD,MAAM,cAAc,GAAG,WAAW,CAChC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAClD,CAAA;IACD,MAAM,YAAY,GAAG,GAAG,aAAa,IAAI,cAAc,EAAE,CAAA;IACzD,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,SAAS,CAClC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,EACtC,MAAM,CAAC,gBAAgB,CACxB,CAAA;IACD,OAAO,GAAG,YAAY,IAAI,WAAW,CAAC,SAAS,CAAC,EAAE,CAAA;AACpD,CAAC"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public interfaces for the SD-JWT VC integration.
|
|
3
|
+
*
|
|
4
|
+
* SD-JWT VC (draft-ietf-oauth-sd-jwt-vc) is one of two W3C VC formats
|
|
5
|
+
* accepted by the EUDI Wallet ARF; the other is ISO mDoc. This module
|
|
6
|
+
* exposes a thin, opinionated wrapper around `@sd-jwt/sd-jwt-vc` that
|
|
7
|
+
* matches Solidus's Ed25519 / DID conventions.
|
|
8
|
+
*
|
|
9
|
+
* For background, see `.claude/plans/2026-05-09-sdjwt-vc-implementation.md`.
|
|
10
|
+
*/
|
|
11
|
+
/** Parameters accepted by [`issueSdJwtVc`]. */
|
|
12
|
+
export interface IssueSdJwtVcParams {
|
|
13
|
+
/**
|
|
14
|
+
* Issuer DID (e.g., `did:solidus:testnet:...`). Becomes the `iss` claim
|
|
15
|
+
* and surfaces the issuer's chain-resolved verification key to verifiers.
|
|
16
|
+
*/
|
|
17
|
+
issuer: string;
|
|
18
|
+
/**
|
|
19
|
+
* Verifiable credential type — an opaque URN per SD-JWT VC §3.2.2.2.
|
|
20
|
+
* Use `https://docs.solidus.network/credentials/{type}` for Solidus
|
|
21
|
+
* native types, or any externally-defined URN for interop.
|
|
22
|
+
*/
|
|
23
|
+
vct: string;
|
|
24
|
+
/**
|
|
25
|
+
* The credential subject. Typically `{ id: did, ...claims }`. The
|
|
26
|
+
* subject `id` is conventionally a holder DID; if absent, the SD-JWT
|
|
27
|
+
* is bearer.
|
|
28
|
+
*/
|
|
29
|
+
subject: Record<string, unknown>;
|
|
30
|
+
/**
|
|
31
|
+
* Issuer's raw 32-byte Ed25519 private key. Same key material used
|
|
32
|
+
* elsewhere in Solidus (chain transactions, `@solidus-network/jwt`).
|
|
33
|
+
*/
|
|
34
|
+
issuerPrivateKey: Uint8Array;
|
|
35
|
+
/**
|
|
36
|
+
* Subject-claim paths that should be disclosable. Each entry is
|
|
37
|
+
* either a top-level key (`'birthdate'`) or a dotted path into a
|
|
38
|
+
* nested object (`'address.street'`). If omitted, every top-level
|
|
39
|
+
* subject claim except `id` is disclosable; nested objects are not
|
|
40
|
+
* auto-expanded — pass explicit paths to selectively disclose them.
|
|
41
|
+
*
|
|
42
|
+
* @example ['birthdate', 'address.street', 'address.city']
|
|
43
|
+
*/
|
|
44
|
+
disclosable?: string[];
|
|
45
|
+
/** RFC 3339 timestamp; sd-jwt-vc maps this to `nbf`. Defaults to now. */
|
|
46
|
+
validFrom?: string;
|
|
47
|
+
/** RFC 3339 timestamp; sd-jwt-vc maps this to `exp`. Optional. */
|
|
48
|
+
validUntil?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Optional 32-byte Ed25519 public key of the *holder*. When provided,
|
|
51
|
+
* the issued SD-JWT embeds a `cnf.jwk` claim binding the credential
|
|
52
|
+
* to this key — required if the verifier is going to enforce a
|
|
53
|
+
* Key-Binding JWT at presentation time. Omit to issue a bearer
|
|
54
|
+
* credential (Phase 1 default).
|
|
55
|
+
*/
|
|
56
|
+
holderPublicKey?: Uint8Array;
|
|
57
|
+
/**
|
|
58
|
+
* Optional reference into a status list (draft-ietf-oauth-status-list).
|
|
59
|
+
* When set, the issued SD-JWT carries `status: { status_list: { uri,
|
|
60
|
+
* idx } }`; verifiers that supply a `statusListFetcher` will fetch
|
|
61
|
+
* the list, look up bit `idx`, and reject the credential if the
|
|
62
|
+
* status indicates revocation.
|
|
63
|
+
*/
|
|
64
|
+
status?: {
|
|
65
|
+
uri: string;
|
|
66
|
+
idx: number;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The compact-serialised SD-JWT VC, plus metadata. The `compact` field
|
|
71
|
+
* is the wire format consumed by holders and verifiers:
|
|
72
|
+
* `<jws>~<disclosure1>~<disclosure2>~`.
|
|
73
|
+
*/
|
|
74
|
+
export interface IssuedSdJwtVc {
|
|
75
|
+
/** Compact-serialised SD-JWT VC: `<jws>~<d1>~...~`. */
|
|
76
|
+
compact: string;
|
|
77
|
+
/** Decoded JWS payload (claims minus the disclosed-but-hashed values). */
|
|
78
|
+
payload: Record<string, unknown>;
|
|
79
|
+
/** Number of disclosable claims encoded. */
|
|
80
|
+
disclosureCount: number;
|
|
81
|
+
}
|
|
82
|
+
/** Parameters accepted by [`verifySdJwtVc`]. */
|
|
83
|
+
export interface VerifySdJwtVcParams {
|
|
84
|
+
/** Compact-serialised SD-JWT VC. */
|
|
85
|
+
compact: string;
|
|
86
|
+
/**
|
|
87
|
+
* Issuer's raw 32-byte Ed25519 *public* key. In production the
|
|
88
|
+
* verifier resolves this from the issuer DID's chain document; this
|
|
89
|
+
* Phase-1 API takes the key explicitly to keep the module decoupled
|
|
90
|
+
* from the chain client.
|
|
91
|
+
*/
|
|
92
|
+
issuerPublicKey: Uint8Array;
|
|
93
|
+
/**
|
|
94
|
+
* If provided, the verifier requires a valid Key-Binding JWT and
|
|
95
|
+
* checks the KB-JWT's `aud` claim against this value. Use this to
|
|
96
|
+
* stop a stolen presentation from being replayed against a different
|
|
97
|
+
* verifier.
|
|
98
|
+
*/
|
|
99
|
+
expectedAudience?: string;
|
|
100
|
+
/**
|
|
101
|
+
* If provided, the verifier requires a valid Key-Binding JWT and
|
|
102
|
+
* checks the KB-JWT's `nonce` claim against this value. The verifier
|
|
103
|
+
* is responsible for generating a fresh nonce per presentation
|
|
104
|
+
* request and remembering it for the duration of the round-trip.
|
|
105
|
+
*/
|
|
106
|
+
expectedNonce?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Callback that fetches the status-list JWT at a given URI. Required
|
|
109
|
+
* to enable revocation checking; if absent the verifier skips the
|
|
110
|
+
* status check (treats every credential as live). In production the
|
|
111
|
+
* caller usually wires this to `fetch()`; tests can use an in-memory
|
|
112
|
+
* map.
|
|
113
|
+
*/
|
|
114
|
+
statusListFetcher?: (uri: string) => Promise<string>;
|
|
115
|
+
/**
|
|
116
|
+
* Verifier callback for the *status list JWT*'s signature. The
|
|
117
|
+
* status list JWT is signed by the issuer (or a status-list-specific
|
|
118
|
+
* key); pass the public key here. If omitted, the same issuerPublicKey
|
|
119
|
+
* used for the SD-JWT is reused — appropriate when the issuer signs
|
|
120
|
+
* its own status lists.
|
|
121
|
+
*/
|
|
122
|
+
statusListIssuerPublicKey?: Uint8Array;
|
|
123
|
+
}
|
|
124
|
+
/** Parameters accepted by [`presentSdJwtVc`]. */
|
|
125
|
+
export interface PresentSdJwtVcParams {
|
|
126
|
+
/** Compact-serialised SD-JWT VC as issued (with all disclosures attached). */
|
|
127
|
+
compact: string;
|
|
128
|
+
/**
|
|
129
|
+
* Paths of the subject claims to reveal in this presentation. Each
|
|
130
|
+
* entry is either a top-level key (`'firstName'`) or a dotted path
|
|
131
|
+
* into a nested object (`'address.street'`). Any disclosure not
|
|
132
|
+
* listed here is omitted from the presented compact form; the
|
|
133
|
+
* verifier still sees the hash but cannot recover the value.
|
|
134
|
+
*
|
|
135
|
+
* @example ['firstName', 'address.street']
|
|
136
|
+
*/
|
|
137
|
+
claimsToReveal: string[];
|
|
138
|
+
/**
|
|
139
|
+
* Holder's raw 32-byte Ed25519 *private* key. Must be the partner of
|
|
140
|
+
* the `holderPublicKey` that was bound at issuance time via `cnf.jwk`.
|
|
141
|
+
* Required because Phase 2 always emits a Key-Binding JWT — bearer
|
|
142
|
+
* presentations stay on the Phase-1 verify path with no `aud`/`nonce`.
|
|
143
|
+
*/
|
|
144
|
+
holderPrivateKey: Uint8Array;
|
|
145
|
+
/**
|
|
146
|
+
* Audience identifier for the verifier (typically the verifier's
|
|
147
|
+
* client_id or origin). Becomes the `aud` claim of the KB-JWT.
|
|
148
|
+
*/
|
|
149
|
+
audience: string;
|
|
150
|
+
/**
|
|
151
|
+
* Fresh, single-use nonce supplied by the verifier. Becomes the
|
|
152
|
+
* `nonce` claim of the KB-JWT.
|
|
153
|
+
*/
|
|
154
|
+
nonce: string;
|
|
155
|
+
}
|
|
156
|
+
/** Result of [`presentSdJwtVc`]. */
|
|
157
|
+
export interface PresentationResult {
|
|
158
|
+
/**
|
|
159
|
+
* Compact-serialised presentation:
|
|
160
|
+
* `<jws>~<revealed_d1>~<revealed_d2>~<kb-jwt>`. Note that the trailing
|
|
161
|
+
* `~` before the KB-JWT is part of the spec.
|
|
162
|
+
*/
|
|
163
|
+
compact: string;
|
|
164
|
+
}
|
|
165
|
+
export interface VerificationResult {
|
|
166
|
+
/** True if signature, hashes, and freshness all check out. */
|
|
167
|
+
valid: boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Reconstructed claims after applying disclosures. Includes hidden
|
|
170
|
+
* fields *only if* the corresponding disclosure was present in the
|
|
171
|
+
* compact form.
|
|
172
|
+
*/
|
|
173
|
+
claims: Record<string, unknown>;
|
|
174
|
+
/** Issuer DID (the `iss` claim). */
|
|
175
|
+
issuer?: string;
|
|
176
|
+
/** Verifiable credential type (`vct` claim). */
|
|
177
|
+
vct?: string;
|
|
178
|
+
/** Reason for verification failure, if any. */
|
|
179
|
+
error?: string;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sdjwt/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAA;IAEd;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAA;IAEX;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAEhC;;;OAGG;IACH,gBAAgB,EAAE,UAAU,CAAA;IAE5B;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IAEtB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,UAAU,CAAA;IAE5B;;;;;;OAMG;IACH,MAAM,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAA;IAEf,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAEhC,4CAA4C;IAC5C,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,gDAAgD;AAChD,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAA;IAEf;;;;;OAKG;IACH,eAAe,EAAE,UAAU,CAAA;IAE3B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAEzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAEpD;;;;;;OAMG;IACH,yBAAyB,CAAC,EAAE,UAAU,CAAA;CACvC;AAED,iDAAiD;AACjD,MAAM,WAAW,oBAAoB;IACnC,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAA;IAEf;;;;;;;;OAQG;IACH,cAAc,EAAE,MAAM,EAAE,CAAA;IAExB;;;;;OAKG;IACH,gBAAgB,EAAE,UAAU,CAAA;IAE5B;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAEhB;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;CACd;AAED,oCAAoC;AACpC,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,8DAA8D;IAC9D,KAAK,EAAE,OAAO,CAAA;IAEd;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAE/B,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAA;CACf"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public interfaces for the SD-JWT VC integration.
|
|
3
|
+
*
|
|
4
|
+
* SD-JWT VC (draft-ietf-oauth-sd-jwt-vc) is one of two W3C VC formats
|
|
5
|
+
* accepted by the EUDI Wallet ARF; the other is ISO mDoc. This module
|
|
6
|
+
* exposes a thin, opinionated wrapper around `@sd-jwt/sd-jwt-vc` that
|
|
7
|
+
* matches Solidus's Ed25519 / DID conventions.
|
|
8
|
+
*
|
|
9
|
+
* For background, see `.claude/plans/2026-05-09-sdjwt-vc-implementation.md`.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sdjwt/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify an SD-JWT VC, optionally including a Key-Binding JWT.
|
|
3
|
+
*
|
|
4
|
+
* Phase 1 verified just the issuer's signature + freshness; Phase 2
|
|
5
|
+
* adds an optional KB-JWT path. When the caller supplies
|
|
6
|
+
* `expectedAudience` and/or `expectedNonce`, the verifier:
|
|
7
|
+
* - requires a KB-JWT to be present in the compact form,
|
|
8
|
+
* - extracts the holder's public key from the SD-JWT's `cnf.jwk`,
|
|
9
|
+
* - verifies the KB-JWT signature against that key,
|
|
10
|
+
* - checks `aud` and `nonce` match the caller's expectations,
|
|
11
|
+
* - confirms `sd_hash` matches the hash of the SD-JWT being presented.
|
|
12
|
+
*
|
|
13
|
+
* If neither expected* is set, the verifier behaves as Phase 1 — bearer
|
|
14
|
+
* presentations remain accepted.
|
|
15
|
+
*
|
|
16
|
+
* KB-JWT parsing is done in this module rather than via sd-jwt-js's
|
|
17
|
+
* `verify()` because sd-jwt-js conflates "extract KB-JWT" and "check
|
|
18
|
+
* nonce" in a single option, leaving us no clean way to surface
|
|
19
|
+
* `aud mismatch` separately from `nonce mismatch`.
|
|
20
|
+
*/
|
|
21
|
+
import type { VerifySdJwtVcParams, VerificationResult } from './types.js';
|
|
22
|
+
export declare function verifySdJwtVc(params: VerifySdJwtVcParams): Promise<VerificationResult>;
|
|
23
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/sdjwt/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAWH,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AA4EzE,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,kBAAkB,CAAC,CAuI7B"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify an SD-JWT VC, optionally including a Key-Binding JWT.
|
|
3
|
+
*
|
|
4
|
+
* Phase 1 verified just the issuer's signature + freshness; Phase 2
|
|
5
|
+
* adds an optional KB-JWT path. When the caller supplies
|
|
6
|
+
* `expectedAudience` and/or `expectedNonce`, the verifier:
|
|
7
|
+
* - requires a KB-JWT to be present in the compact form,
|
|
8
|
+
* - extracts the holder's public key from the SD-JWT's `cnf.jwk`,
|
|
9
|
+
* - verifies the KB-JWT signature against that key,
|
|
10
|
+
* - checks `aud` and `nonce` match the caller's expectations,
|
|
11
|
+
* - confirms `sd_hash` matches the hash of the SD-JWT being presented.
|
|
12
|
+
*
|
|
13
|
+
* If neither expected* is set, the verifier behaves as Phase 1 — bearer
|
|
14
|
+
* presentations remain accepted.
|
|
15
|
+
*
|
|
16
|
+
* KB-JWT parsing is done in this module rather than via sd-jwt-js's
|
|
17
|
+
* `verify()` because sd-jwt-js conflates "extract KB-JWT" and "check
|
|
18
|
+
* nonce" in a single option, leaving us no clean way to surface
|
|
19
|
+
* `aud mismatch` separately from `nonce mismatch`.
|
|
20
|
+
*/
|
|
21
|
+
import { SDJwtVcInstance } from '@sd-jwt/sd-jwt-vc';
|
|
22
|
+
import * as ed from '@noble/ed25519';
|
|
23
|
+
import { sha256 } from '@noble/hashes/sha2';
|
|
24
|
+
import { ed25519PublicKeyFromJwk, makeEd25519Verifier, sdJwtHasher, } from './signer.js';
|
|
25
|
+
function fromBase64Url(input) {
|
|
26
|
+
const padded = input
|
|
27
|
+
.replace(/-/g, '+')
|
|
28
|
+
.replace(/_/g, '/')
|
|
29
|
+
.padEnd(input.length + ((4 - (input.length % 4)) % 4), '=');
|
|
30
|
+
return new Uint8Array(Buffer.from(padded, 'base64'));
|
|
31
|
+
}
|
|
32
|
+
function toBase64Url(input) {
|
|
33
|
+
return Buffer.from(input)
|
|
34
|
+
.toString('base64')
|
|
35
|
+
.replace(/\+/g, '-')
|
|
36
|
+
.replace(/\//g, '_')
|
|
37
|
+
.replace(/=/g, '');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Decode (without verifying) the KB-JWT off the end of a compact SD-JWT.
|
|
41
|
+
*
|
|
42
|
+
* The compact form is `<jws>~<d1>~<d2>~<kb-jwt>`. The KB-JWT is the
|
|
43
|
+
* final non-empty segment; the `<jws>~<d1>~...~` prefix (with the
|
|
44
|
+
* trailing `~` retained) is what `sd_hash` covers per spec §3.3.
|
|
45
|
+
*/
|
|
46
|
+
function extractKbJwt(compact) {
|
|
47
|
+
const lastTilde = compact.lastIndexOf('~');
|
|
48
|
+
if (lastTilde < 0)
|
|
49
|
+
return null;
|
|
50
|
+
const kbCompact = compact.slice(lastTilde + 1);
|
|
51
|
+
if (kbCompact.length === 0)
|
|
52
|
+
return null;
|
|
53
|
+
const sdJwtBody = compact.slice(0, lastTilde + 1); // includes trailing `~`
|
|
54
|
+
const segments = kbCompact.split('.');
|
|
55
|
+
if (segments.length !== 3)
|
|
56
|
+
return null;
|
|
57
|
+
let payload;
|
|
58
|
+
try {
|
|
59
|
+
payload = JSON.parse(new TextDecoder().decode(fromBase64Url(segments[1])));
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return { kbCompact, sdJwtBody, payload };
|
|
65
|
+
}
|
|
66
|
+
async function verifyKbSignature(kbCompact, holderPublicKey) {
|
|
67
|
+
const segments = kbCompact.split('.');
|
|
68
|
+
if (segments.length !== 3)
|
|
69
|
+
return false;
|
|
70
|
+
const signingInput = `${segments[0]}.${segments[1]}`;
|
|
71
|
+
const signature = fromBase64Url(segments[2]);
|
|
72
|
+
try {
|
|
73
|
+
return await ed.verifyAsync(signature, new TextEncoder().encode(signingInput), holderPublicKey);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export async function verifySdJwtVc(params) {
|
|
80
|
+
if (params.issuerPublicKey.length !== 32) {
|
|
81
|
+
return {
|
|
82
|
+
valid: false,
|
|
83
|
+
claims: {},
|
|
84
|
+
error: `issuerPublicKey must be 32 bytes, got ${params.issuerPublicKey.length}`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const requireKb = params.expectedAudience !== undefined ||
|
|
88
|
+
params.expectedNonce !== undefined;
|
|
89
|
+
const statusListVerifier = params.statusListIssuerPublicKey
|
|
90
|
+
? makeEd25519Verifier(params.statusListIssuerPublicKey)
|
|
91
|
+
: makeEd25519Verifier(params.issuerPublicKey);
|
|
92
|
+
const sdjwt = new SDJwtVcInstance({
|
|
93
|
+
verifier: makeEd25519Verifier(params.issuerPublicKey),
|
|
94
|
+
hasher: sdJwtHasher,
|
|
95
|
+
hashAlg: 'sha-256',
|
|
96
|
+
loadTypeMetadataFormat: false,
|
|
97
|
+
// Wire status-list lookup if the caller supplied a fetcher.
|
|
98
|
+
// sd-jwt-vc fetches the status-list JWT, verifies its signature,
|
|
99
|
+
// looks up `idx`, and (by default) treats any non-zero status as
|
|
100
|
+
// revoked.
|
|
101
|
+
...(params.statusListFetcher !== undefined
|
|
102
|
+
? {
|
|
103
|
+
statusListFetcher: params.statusListFetcher,
|
|
104
|
+
statusVerifier: statusListVerifier,
|
|
105
|
+
}
|
|
106
|
+
: {}),
|
|
107
|
+
});
|
|
108
|
+
let payload;
|
|
109
|
+
try {
|
|
110
|
+
const result = await sdjwt.verify(params.compact);
|
|
111
|
+
payload = result.payload;
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
return {
|
|
115
|
+
valid: false,
|
|
116
|
+
claims: {},
|
|
117
|
+
error: e instanceof Error ? e.message : String(e),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (requireKb) {
|
|
121
|
+
const parsed = extractKbJwt(params.compact);
|
|
122
|
+
if (!parsed) {
|
|
123
|
+
return {
|
|
124
|
+
valid: false,
|
|
125
|
+
claims: {},
|
|
126
|
+
error: 'KB-JWT required but not present in compact form',
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
const cnf = payload.cnf;
|
|
130
|
+
if (!cnf?.jwk) {
|
|
131
|
+
return {
|
|
132
|
+
valid: false,
|
|
133
|
+
claims: {},
|
|
134
|
+
error: 'SD-JWT does not bind a holder key (`cnf.jwk` missing)',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
let holderPk;
|
|
138
|
+
try {
|
|
139
|
+
holderPk = ed25519PublicKeyFromJwk(cnf.jwk);
|
|
140
|
+
}
|
|
141
|
+
catch (e) {
|
|
142
|
+
return {
|
|
143
|
+
valid: false,
|
|
144
|
+
claims: {},
|
|
145
|
+
error: `cnf.jwk invalid: ${e instanceof Error ? e.message : String(e)}`,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const sigOk = await verifyKbSignature(parsed.kbCompact, holderPk);
|
|
149
|
+
if (!sigOk) {
|
|
150
|
+
return {
|
|
151
|
+
valid: false,
|
|
152
|
+
claims: {},
|
|
153
|
+
error: 'KB-JWT signature does not match the holder key from cnf.jwk',
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (params.expectedAudience !== undefined &&
|
|
157
|
+
parsed.payload.aud !== params.expectedAudience) {
|
|
158
|
+
return {
|
|
159
|
+
valid: false,
|
|
160
|
+
claims: {},
|
|
161
|
+
error: `KB-JWT aud mismatch: expected ${params.expectedAudience}, got ${parsed.payload.aud ?? '<missing>'}`,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
if (params.expectedNonce !== undefined &&
|
|
165
|
+
parsed.payload.nonce !== params.expectedNonce) {
|
|
166
|
+
return {
|
|
167
|
+
valid: false,
|
|
168
|
+
claims: {},
|
|
169
|
+
error: `KB-JWT nonce mismatch: expected ${params.expectedNonce}, got ${parsed.payload.nonce ?? '<missing>'}`,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
// Confirm sd_hash matches the SHA-256 of the SD-JWT body (everything
|
|
173
|
+
// before the KB-JWT, with the trailing `~` retained per spec).
|
|
174
|
+
if (parsed.payload.sd_hash !== undefined) {
|
|
175
|
+
const expectedHash = toBase64Url(sha256(new TextEncoder().encode(parsed.sdJwtBody)));
|
|
176
|
+
if (parsed.payload.sd_hash !== expectedHash) {
|
|
177
|
+
return {
|
|
178
|
+
valid: false,
|
|
179
|
+
claims: {},
|
|
180
|
+
error: 'KB-JWT sd_hash does not cover the presented SD-JWT body',
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// sd-jwt-js's verify() reconstructs disclosed claims and merges
|
|
186
|
+
// them into the payload, dropping the `_sd` arrays. The caller
|
|
187
|
+
// should never see SD-JWT housekeeping fields.
|
|
188
|
+
const claims = {};
|
|
189
|
+
for (const [k, v] of Object.entries(payload)) {
|
|
190
|
+
if (k === '_sd' || k === '_sd_alg' || k === 'cnf')
|
|
191
|
+
continue;
|
|
192
|
+
claims[k] = v;
|
|
193
|
+
}
|
|
194
|
+
const out = { valid: true, claims };
|
|
195
|
+
if (typeof payload['iss'] === 'string')
|
|
196
|
+
out.issuer = payload['iss'];
|
|
197
|
+
if (typeof payload['vct'] === 'string')
|
|
198
|
+
out.vct = payload['vct'];
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/sdjwt/verify.ts"],"names":[],"mappings":"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"}
|
package/dist/stub/credentials.js
CHANGED
|
@@ -3,12 +3,12 @@ import { getSql } from './db.js';
|
|
|
3
3
|
import { sign, verify as cryptoVerify } from './crypto.js';
|
|
4
4
|
function rowToVC(row) {
|
|
5
5
|
return {
|
|
6
|
-
'@context': ['https://www.w3.org/
|
|
6
|
+
'@context': ['https://www.w3.org/ns/credentials/v2'],
|
|
7
7
|
id: row.credential_id,
|
|
8
8
|
type: row.type,
|
|
9
9
|
issuer: row.issuer_did,
|
|
10
|
-
|
|
11
|
-
...(row.expires_at && {
|
|
10
|
+
validFrom: row.issued_at.toISOString(),
|
|
11
|
+
...(row.expires_at && { validUntil: row.expires_at.toISOString() }),
|
|
12
12
|
credentialSubject: { id: row.subject_did, ...row.claims },
|
|
13
13
|
proof: {
|
|
14
14
|
type: 'Ed25519Signature2020',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/stub/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAGxC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,aAAa,CAAA;AAc1D,SAAS,OAAO,CAAC,GAAkB;IACjC,OAAO;QACL,UAAU,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/stub/credentials.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidus-network/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Solidus Network SDK — DID resolution, verifiable credential issuance and verification, and on-chain queries via JSON-RPC.",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Solidus Network SDK — DID resolution, verifiable credential issuance and verification, SD-JWT VC (EUDI-compatible), and on-chain queries via JSON-RPC.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -15,12 +15,14 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@noble/ed25519": "^2.1.0",
|
|
17
17
|
"@noble/hashes": "^1.5.0",
|
|
18
|
-
"@
|
|
19
|
-
"@
|
|
18
|
+
"@sd-jwt/sd-jwt-vc": "^0.19.0",
|
|
19
|
+
"@sd-jwt/types": "^0.19.0",
|
|
20
|
+
"@solidus-network/auth": "0.3.0",
|
|
21
|
+
"@solidus-network/types": "0.3.0",
|
|
20
22
|
"bs58": "^6.0.0",
|
|
21
23
|
"postgres": "^3.4.4"
|
|
22
24
|
},
|
|
23
|
-
"keywords": ["solidus", "did", "verifiable-credentials", "vc", "blockchain", "decentralized-identity", "sdk"],
|
|
25
|
+
"keywords": ["solidus", "did", "verifiable-credentials", "vc", "sd-jwt", "sd-jwt-vc", "eudi", "blockchain", "decentralized-identity", "sdk"],
|
|
24
26
|
"author": "Solidus Network (https://solidus.network)",
|
|
25
27
|
"license": "Apache-2.0",
|
|
26
28
|
"homepage": "https://solidus.network",
|