@onchaindiligence/sdk 0.2.0 → 0.3.1
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 +95 -8
- package/conformance/attestation-v1-v2-vectors.json +98 -0
- package/conformance/rfc8785-vectors.json +31 -0
- package/dist/commerce/client.d.ts +134 -0
- package/dist/commerce/client.js +511 -0
- package/dist/commerce/evidenceExport.d.ts +51 -0
- package/dist/commerce/evidenceExport.js +44 -0
- package/dist/commerce/executor.d.ts +64 -0
- package/dist/commerce/executor.js +19 -0
- package/dist/commerce/index.d.ts +29 -0
- package/dist/commerce/index.js +29 -0
- package/dist/commerce/mockExecutor.d.ts +41 -0
- package/dist/commerce/mockExecutor.js +74 -0
- package/dist/commerce/nodeFileRecoveryStore.d.ts +17 -0
- package/dist/commerce/nodeFileRecoveryStore.js +126 -0
- package/dist/commerce/policyTemplates.d.ts +48 -0
- package/dist/commerce/policyTemplates.js +54 -0
- package/dist/commerce/recoveryStore.d.ts +73 -0
- package/dist/commerce/recoveryStore.js +77 -0
- package/dist/commerce/results.d.ts +90 -0
- package/dist/commerce/results.js +3 -0
- package/dist/commerce/types.d.ts +147 -0
- package/dist/commerce/types.js +13 -0
- package/dist/commerce/x402Executor.d.ts +43 -0
- package/dist/commerce/x402Executor.js +222 -0
- package/dist/index.d.ts +36 -32
- package/dist/index.js +155 -86
- package/dist/verification.d.ts +109 -0
- package/dist/verification.js +621 -0
- package/package.json +19 -3
package/dist/index.js
CHANGED
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
* build a payment header, or retry a request by hand.
|
|
23
23
|
*/
|
|
24
24
|
import { Mppx, tempo } from 'mppx/client';
|
|
25
|
+
import { DEFAULT_ATTESTATION_ISSUER, verifyAttestationOffline, } from './verification.js';
|
|
26
|
+
export * from './verification.js';
|
|
25
27
|
export class OnchainDiligenceError extends Error {
|
|
26
28
|
status;
|
|
27
29
|
constructor(status, message) {
|
|
@@ -31,12 +33,136 @@ export class OnchainDiligenceError extends Error {
|
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
const DEFAULT_BASE_URL = 'https://api.onchaindiligence.com';
|
|
36
|
+
export async function resolveAttestationKeyOnline(keyId, options = {}) {
|
|
37
|
+
const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
|
|
38
|
+
if (!options.fetch && !globalThis.fetch)
|
|
39
|
+
throw new Error('fetch is unavailable in this runtime');
|
|
40
|
+
// `globalThis.fetch` is a WebIDL operation on the global object -- calling
|
|
41
|
+
// it through ANY indirection (a local variable, a class property) other
|
|
42
|
+
// than the bare `fetch(...)` identifier detaches it from its required
|
|
43
|
+
// receiver, which throws "Illegal invocation" in real browsers (invisible
|
|
44
|
+
// under Node, which does not enforce this). Binding to globalThis is what
|
|
45
|
+
// makes storing/passing it around safe.
|
|
46
|
+
const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
47
|
+
const exact = await fetchImpl(`${baseUrl}/.well-known/attestation-keys/${encodeURIComponent(keyId)}`);
|
|
48
|
+
if (exact.ok) {
|
|
49
|
+
const payload = (await exact.json());
|
|
50
|
+
if (!payload.key || payload.key.key_id !== keyId) {
|
|
51
|
+
throw new Error('attestation key registry returned an invalid or mismatched key');
|
|
52
|
+
}
|
|
53
|
+
return payload.key;
|
|
54
|
+
}
|
|
55
|
+
if (exact.status !== 404) {
|
|
56
|
+
throw new OnchainDiligenceError(exact.status, 'could not fetch attestation public key');
|
|
57
|
+
}
|
|
58
|
+
const legacy = await fetchImpl(`${baseUrl}/.well-known/attestation-key`);
|
|
59
|
+
if (!legacy.ok) {
|
|
60
|
+
throw new OnchainDiligenceError(legacy.status, 'could not fetch attestation public key');
|
|
61
|
+
}
|
|
62
|
+
const text = await legacy.text();
|
|
63
|
+
let reportedKeyId = '';
|
|
64
|
+
let pem = text.trim();
|
|
65
|
+
let algorithm = 'ed25519';
|
|
66
|
+
let status = 'active';
|
|
67
|
+
if (!pem.includes('BEGIN PUBLIC KEY')) {
|
|
68
|
+
const payload = JSON.parse(text);
|
|
69
|
+
reportedKeyId = payload.key_id || '';
|
|
70
|
+
pem = (payload.public_key_pem || payload.publicKey || payload.pem || payload.key || '').trim();
|
|
71
|
+
algorithm = payload.algorithm || algorithm;
|
|
72
|
+
status = payload.status || status;
|
|
73
|
+
}
|
|
74
|
+
if (reportedKeyId !== keyId || !pem.includes('BEGIN PUBLIC KEY') || algorithm !== 'ed25519') {
|
|
75
|
+
throw new Error('legacy attestation-key endpoint did not return the requested key_id');
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
key_id: keyId,
|
|
79
|
+
algorithm: 'ed25519',
|
|
80
|
+
public_key_pem: pem,
|
|
81
|
+
status,
|
|
82
|
+
valid_from: null,
|
|
83
|
+
valid_until: null,
|
|
84
|
+
status_changed_at: null,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** Validate and return the complete signed envelope required by `/anchor`. */
|
|
88
|
+
export function buildAnchorRequest(envelope) {
|
|
89
|
+
if (!envelope ||
|
|
90
|
+
typeof envelope !== 'object' ||
|
|
91
|
+
!Object.hasOwn(envelope, 'data') ||
|
|
92
|
+
!envelope.attestation ||
|
|
93
|
+
typeof envelope.attestation !== 'object' ||
|
|
94
|
+
envelope.attestation.signed !== true) {
|
|
95
|
+
throw new TypeError('anchor requires the complete signed attestation envelope');
|
|
96
|
+
}
|
|
97
|
+
return envelope;
|
|
98
|
+
}
|
|
99
|
+
/** Explicit online-discovery wrapper around the zero-network verifier core. */
|
|
100
|
+
export async function verifyAttestationOnline(signed, options = {}) {
|
|
101
|
+
let parsed = signed;
|
|
102
|
+
if (typeof signed === 'string') {
|
|
103
|
+
try {
|
|
104
|
+
parsed = JSON.parse(signed);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return verifyAttestationOffline(signed, { keys: [] }, options);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const keyId = parsed?.attestation?.key_id;
|
|
111
|
+
if (typeof keyId !== 'string') {
|
|
112
|
+
return verifyAttestationOffline(signed, { keys: [] }, options);
|
|
113
|
+
}
|
|
114
|
+
const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
|
|
115
|
+
let record;
|
|
116
|
+
try {
|
|
117
|
+
record = await resolveAttestationKeyOnline(keyId, { baseUrl, fetch: options.fetch });
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
const offline = await verifyAttestationOffline(signed, { keys: [] }, options);
|
|
121
|
+
if (offline.state === 'INVALID')
|
|
122
|
+
return offline;
|
|
123
|
+
return {
|
|
124
|
+
...offline,
|
|
125
|
+
state: 'UNVERIFIABLE',
|
|
126
|
+
valid: false,
|
|
127
|
+
code: 'online_key_resolution_failed',
|
|
128
|
+
reason: error instanceof Error ? error.message : 'Online key resolution failed.',
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const material = {
|
|
132
|
+
keys: [record],
|
|
133
|
+
issuer: options.expectedIssuer ?? DEFAULT_ATTESTATION_ISSUER,
|
|
134
|
+
trust_source: `online-registry:${baseUrl}`,
|
|
135
|
+
};
|
|
136
|
+
const offline = await verifyAttestationOffline(signed, material, options);
|
|
137
|
+
const trustDecision = typeof options.trustRegistry === 'function'
|
|
138
|
+
? await options.trustRegistry(record, { baseUrl })
|
|
139
|
+
: options.trustRegistry === true;
|
|
140
|
+
if (trustDecision || offline.state === 'INVALID')
|
|
141
|
+
return offline;
|
|
142
|
+
return {
|
|
143
|
+
...offline,
|
|
144
|
+
state: 'UNVERIFIABLE',
|
|
145
|
+
valid: false,
|
|
146
|
+
code: 'online_registry_not_trusted',
|
|
147
|
+
reason: 'The key was discovered online but the caller did not trust that registry as identity authority.',
|
|
148
|
+
trusted: false,
|
|
149
|
+
components: {
|
|
150
|
+
...offline.components,
|
|
151
|
+
identity: {
|
|
152
|
+
state: 'UNKNOWN',
|
|
153
|
+
code: 'online_registry_not_trusted',
|
|
154
|
+
message: 'Online key discovery is not an out-of-band trust decision.',
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
34
159
|
export class OnchainDiligence {
|
|
35
160
|
baseUrl;
|
|
161
|
+
expectedAttestationIssuer;
|
|
36
162
|
fetch;
|
|
37
|
-
attestationKeyPem = null;
|
|
38
163
|
constructor(opts) {
|
|
39
164
|
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
|
|
165
|
+
this.expectedAttestationIssuer = opts.expectedAttestationIssuer ?? DEFAULT_ATTESTATION_ISSUER;
|
|
40
166
|
// Payment-aware fetch: transparently answers 402 challenges and retries.
|
|
41
167
|
const client = Mppx.create({ methods: [tempo({ account: opts.account })] });
|
|
42
168
|
this.fetch = client.fetch;
|
|
@@ -143,9 +269,9 @@ export class OnchainDiligence {
|
|
|
143
269
|
items,
|
|
144
270
|
};
|
|
145
271
|
}
|
|
146
|
-
/** Anchor
|
|
147
|
-
anchor(
|
|
148
|
-
return this.post(`/anchor`,
|
|
272
|
+
/** Anchor a complete authentic attestation envelope on Tempo (paid). */
|
|
273
|
+
anchor(envelope) {
|
|
274
|
+
return this.post(`/anchor`, buildAnchorRequest(envelope));
|
|
149
275
|
}
|
|
150
276
|
// --- Free endpoints ------------------------------------------------------
|
|
151
277
|
/** Check whether an attestation has been anchored on-chain (free). */
|
|
@@ -159,93 +285,36 @@ export class OnchainDiligence {
|
|
|
159
285
|
// --- Verification (local, free, no trust in this SDK or the server) -------
|
|
160
286
|
/**
|
|
161
287
|
* Verify a signed attestation locally. Fetches the server's published
|
|
162
|
-
* Ed25519
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* this SDK.
|
|
288
|
+
* exact Ed25519 key identified by `key_id` (cached), then verifies either
|
|
289
|
+
* the domain-separated RFC 8785 version 2 input or the legacy version 1
|
|
290
|
+
* JSON.stringify input. Revoked/compromised keys remain cryptographically
|
|
291
|
+
* checkable but return `valid: false` and `trusted: false`.
|
|
167
292
|
*
|
|
168
293
|
* Uses WebCrypto (`globalThis.crypto.subtle`) so it runs dependency-free in
|
|
169
294
|
* Node 18+, edge runtimes, and modern browsers.
|
|
170
295
|
*/
|
|
171
|
-
async verifyAttestation(signed) {
|
|
172
|
-
const att = signed?.attestation;
|
|
173
|
-
if (!att || att.signed === false)
|
|
174
|
-
return { valid: false, reason: 'response is not signed' };
|
|
175
|
-
if (!att.signature || !att.key_id || !att.issued_at) {
|
|
176
|
-
return { valid: false, reason: 'attestation is missing signature, key_id, or issued_at' };
|
|
177
|
-
}
|
|
178
|
-
if (att.algorithm && att.algorithm !== 'ed25519') {
|
|
179
|
-
return { valid: false, reason: `unsupported algorithm: ${att.algorithm}`, keyId: att.key_id };
|
|
180
|
-
}
|
|
181
|
-
const subtle = globalThis.crypto?.subtle;
|
|
182
|
-
if (!subtle)
|
|
183
|
-
return { valid: false, reason: 'WebCrypto (crypto.subtle) is unavailable in this runtime' };
|
|
184
|
-
let key;
|
|
185
|
-
try {
|
|
186
|
-
const pem = await this.getAttestationKeyPem();
|
|
187
|
-
key = await subtle.importKey('spki', pemToDer(pem), { name: 'Ed25519' }, false, ['verify']);
|
|
188
|
-
}
|
|
189
|
-
catch (err) {
|
|
190
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
191
|
-
return { valid: false, reason: `could not load public key: ${msg}`, keyId: att.key_id };
|
|
192
|
-
}
|
|
193
|
-
const signingInput = JSON.stringify({
|
|
194
|
-
data: signed.data,
|
|
195
|
-
issued_at: att.issued_at,
|
|
196
|
-
key_id: att.key_id,
|
|
197
|
-
});
|
|
198
|
-
const ok = await subtle.verify('Ed25519', key, b64urlToBytes(att.signature), new TextEncoder().encode(signingInput));
|
|
199
|
-
return ok
|
|
200
|
-
? { valid: true, keyId: att.key_id }
|
|
201
|
-
: { valid: false, reason: 'signature does not match', keyId: att.key_id };
|
|
202
|
-
}
|
|
203
296
|
/**
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
* exposing the PEM under a common field name.
|
|
297
|
+
* Compatibility online wrapper. Prefer the standalone zero-network
|
|
298
|
+
* verifyAttestationOffline() with caller-supplied trust material.
|
|
207
299
|
*/
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
throw new Error('attestation-key endpoint did not return a PEM public key');
|
|
228
|
-
}
|
|
229
|
-
this.attestationKeyPem = pem;
|
|
230
|
-
return pem;
|
|
300
|
+
verifyAttestation(signed) {
|
|
301
|
+
return verifyAttestationOnline(signed, {
|
|
302
|
+
baseUrl: this.baseUrl,
|
|
303
|
+
expectedIssuer: this.expectedAttestationIssuer,
|
|
304
|
+
fetch: this.fetch,
|
|
305
|
+
// This preserves the historical SDK behavior: constructing this client
|
|
306
|
+
// explicitly chooses its configured HTTPS issuer registry as authority.
|
|
307
|
+
trustRegistry: true,
|
|
308
|
+
// Compatibility until production publishes a real activation boundary.
|
|
309
|
+
requireValidFrom: false,
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
verifyAttestationOnline(signed, options = {}) {
|
|
313
|
+
return verifyAttestationOnline(signed, {
|
|
314
|
+
...options,
|
|
315
|
+
baseUrl: this.baseUrl,
|
|
316
|
+
expectedIssuer: options.expectedIssuer ?? this.expectedAttestationIssuer,
|
|
317
|
+
fetch: this.fetch,
|
|
318
|
+
});
|
|
231
319
|
}
|
|
232
|
-
}
|
|
233
|
-
// --- Internal helpers (isomorphic: no Buffer, no Node built-ins) ------------
|
|
234
|
-
/** Decode a PEM (SPKI) public key to its raw DER bytes. */
|
|
235
|
-
function pemToDer(pem) {
|
|
236
|
-
const b64 = pem.replace(/-----[^-]+-----/g, '').replace(/\s+/g, '');
|
|
237
|
-
const bin = atob(b64);
|
|
238
|
-
const out = new Uint8Array(bin.length);
|
|
239
|
-
for (let i = 0; i < bin.length; i++)
|
|
240
|
-
out[i] = bin.charCodeAt(i);
|
|
241
|
-
return out;
|
|
242
|
-
}
|
|
243
|
-
/** Decode a base64url string to bytes. */
|
|
244
|
-
function b64urlToBytes(s) {
|
|
245
|
-
const b64 = s.replace(/-/g, '+').replace(/_/g, '/').padEnd(Math.ceil(s.length / 4) * 4, '=');
|
|
246
|
-
const bin = atob(b64);
|
|
247
|
-
const out = new Uint8Array(bin.length);
|
|
248
|
-
for (let i = 0; i < bin.length; i++)
|
|
249
|
-
out[i] = bin.charCodeAt(i);
|
|
250
|
-
return out;
|
|
251
320
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-network verification for existing OnChainDiligence attestations.
|
|
3
|
+
*
|
|
4
|
+
* This module deliberately has no HTTP client and never discovers keys. The
|
|
5
|
+
* caller supplies the exact key records it has independently chosen to trust.
|
|
6
|
+
* Online discovery is implemented separately in index.ts as a convenience
|
|
7
|
+
* wrapper around this core.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ATTESTATION_V2_SCHEMA = "onchaindiligence.attestation.v2";
|
|
10
|
+
export declare const DEFAULT_ATTESTATION_ISSUER = "https://api.onchaindiligence.com";
|
|
11
|
+
export declare const COMPLIANCE_ATTESTATION_PURPOSE = "compliance-screening-result";
|
|
12
|
+
export declare const FIXTURE_ATTESTATION_PURPOSE = "verification-fixture";
|
|
13
|
+
export type VerificationState = 'VALID' | 'INVALID' | 'UNVERIFIABLE';
|
|
14
|
+
export type ComponentState = 'PASS' | 'FAIL' | 'UNKNOWN' | 'NOT_CHECKED';
|
|
15
|
+
export type AttestationKeyStatus = 'active' | 'retired' | 'revoked' | 'compromised';
|
|
16
|
+
export interface Attestation {
|
|
17
|
+
signed: boolean;
|
|
18
|
+
schema_version?: string;
|
|
19
|
+
issuer?: string;
|
|
20
|
+
purpose?: string;
|
|
21
|
+
key_id?: string;
|
|
22
|
+
algorithm?: string;
|
|
23
|
+
canonicalization?: string;
|
|
24
|
+
signature?: string;
|
|
25
|
+
issued_at?: string;
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
export interface Signed<T> {
|
|
29
|
+
data: T;
|
|
30
|
+
attestation: Attestation;
|
|
31
|
+
}
|
|
32
|
+
export interface AttestationKeyRecord {
|
|
33
|
+
key_id: string;
|
|
34
|
+
algorithm: 'ed25519';
|
|
35
|
+
public_key_pem: string;
|
|
36
|
+
status: AttestationKeyStatus;
|
|
37
|
+
valid_from: string | null;
|
|
38
|
+
valid_until: string | null;
|
|
39
|
+
status_changed_at?: string | null;
|
|
40
|
+
status_reason?: string;
|
|
41
|
+
replacement_key_id?: string | null;
|
|
42
|
+
compromised_at?: string | null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Passing this object is an explicit caller trust decision. A key embedded in
|
|
46
|
+
* an attestation or downloaded from an arbitrary URL MUST NOT be copied here
|
|
47
|
+
* automatically.
|
|
48
|
+
*/
|
|
49
|
+
export interface TrustedAttestationKeySet {
|
|
50
|
+
keys: readonly AttestationKeyRecord[];
|
|
51
|
+
/** Optional identity namespace represented by these trusted records. */
|
|
52
|
+
issuer?: string;
|
|
53
|
+
/** Human/machine-readable description of the out-of-band trust source. */
|
|
54
|
+
trust_source?: string;
|
|
55
|
+
/** Reserved for future signed registry snapshot/root policy. */
|
|
56
|
+
registry_version?: number;
|
|
57
|
+
}
|
|
58
|
+
export interface VerificationComponent {
|
|
59
|
+
state: ComponentState;
|
|
60
|
+
code: string;
|
|
61
|
+
message: string;
|
|
62
|
+
}
|
|
63
|
+
export interface AttestationVerificationComponents {
|
|
64
|
+
structure: VerificationComponent;
|
|
65
|
+
signature: VerificationComponent;
|
|
66
|
+
identity: VerificationComponent;
|
|
67
|
+
lifecycle: VerificationComponent;
|
|
68
|
+
timestamp: VerificationComponent;
|
|
69
|
+
key_window: VerificationComponent;
|
|
70
|
+
freshness: VerificationComponent;
|
|
71
|
+
anchor: VerificationComponent;
|
|
72
|
+
}
|
|
73
|
+
export interface AttestationVerificationResult {
|
|
74
|
+
state: VerificationState;
|
|
75
|
+
/** Compatibility convenience. Security-sensitive callers should use state. */
|
|
76
|
+
valid: boolean;
|
|
77
|
+
code: string;
|
|
78
|
+
reason: string;
|
|
79
|
+
schemaVersion?: string;
|
|
80
|
+
keyId?: string;
|
|
81
|
+
keyStatus?: AttestationKeyStatus;
|
|
82
|
+
cryptographicallyValid?: boolean;
|
|
83
|
+
trusted?: boolean;
|
|
84
|
+
components: AttestationVerificationComponents;
|
|
85
|
+
warnings: string[];
|
|
86
|
+
}
|
|
87
|
+
export interface VerifyAttestationOptions {
|
|
88
|
+
expectedIssuer?: string;
|
|
89
|
+
allowedPurposes?: readonly string[];
|
|
90
|
+
/** Default true. A missing active valid_from is UNVERIFIABLE. */
|
|
91
|
+
requireValidFrom?: boolean;
|
|
92
|
+
/** Evaluate business freshness separately from signature/key validity. */
|
|
93
|
+
maxAgeMs?: number;
|
|
94
|
+
/** Injected for deterministic verification/tests. */
|
|
95
|
+
now?: Date | number | string;
|
|
96
|
+
/** Default five minutes. */
|
|
97
|
+
maxFutureSkewMs?: number;
|
|
98
|
+
}
|
|
99
|
+
/** RFC 8785 canonical JSON for values in the I-JSON data model. */
|
|
100
|
+
export declare function canonicalizeJson(value: unknown): string;
|
|
101
|
+
/**
|
|
102
|
+
* Parse JSON while rejecting duplicate object member names. JSON.parse keeps
|
|
103
|
+
* the last duplicate, which is unsafe for signed formats because another
|
|
104
|
+
* implementation may keep the first.
|
|
105
|
+
*/
|
|
106
|
+
export declare function parseJsonNoDuplicateKeys(text: string, maxDepth?: number): unknown;
|
|
107
|
+
export declare function deriveAttestationKeyId(publicKeyPem: string): Promise<string>;
|
|
108
|
+
/** Verify using only the supplied envelope and caller-trusted key records. */
|
|
109
|
+
export declare function verifyAttestationOffline(input: unknown, trustMaterial: TrustedAttestationKeySet, options?: VerifyAttestationOptions): Promise<AttestationVerificationResult>;
|