@ocap/mcrypto 1.29.22 → 1.29.23

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.
@@ -0,0 +1,512 @@
1
+ import { __exportAll } from "./_virtual/rolldown_runtime.mjs";
2
+ import { sha256, sha384, sha512 } from "@noble/hashes/sha2.js";
3
+ import { secp256k1 } from "@noble/curves/secp256k1";
4
+ import { p256 } from "@noble/curves/p256";
5
+ import { p384 } from "@noble/curves/p384";
6
+ import { p521 } from "@noble/curves/p521";
7
+
8
+ //#region src/webauthn.ts
9
+ /**
10
+ * Lightweight WebAuthn/passkey utilities — replaces @simplewebauthn/server/helpers.
11
+ *
12
+ * Provides COSE constants, CBOR-based credential public key decoding, base64url helpers,
13
+ * authenticator data parsing, and ECDSA signature verification using @noble/curves.
14
+ *
15
+ * Designed for environments sensitive to bundle size (e.g. Cloudflare Workers).
16
+ */
17
+ var webauthn_exports = /* @__PURE__ */ __exportAll({
18
+ COSEALG: () => COSEALG,
19
+ COSECRV: () => COSECRV,
20
+ COSEKEYS: () => COSEKEYS,
21
+ COSEKTY: () => COSEKTY,
22
+ cose: () => cose,
23
+ decodeClientDataJSON: () => decodeClientDataJSON,
24
+ generateAuthenticationOptions: () => generateAuthenticationOptions,
25
+ generateChallenge: () => generateChallenge,
26
+ generateRegistrationOptions: () => generateRegistrationOptions,
27
+ isoBase64URL: () => isoBase64URL,
28
+ isoCBOR: () => isoCBOR,
29
+ isoUint8Array: () => isoUint8Array,
30
+ parseAuthenticatorData: () => parseAuthenticatorData,
31
+ toHash: () => toHash,
32
+ verifyRegistrationResponse: () => verifyRegistrationResponse,
33
+ verifySignature: () => verifySignature
34
+ });
35
+ const COSEKEYS = {
36
+ kty: 1,
37
+ alg: 3,
38
+ crv: -1,
39
+ x: -2,
40
+ y: -3,
41
+ n: -1,
42
+ e: -2
43
+ };
44
+ const COSEKTY = {
45
+ OKP: 1,
46
+ EC2: 2,
47
+ RSA: 3
48
+ };
49
+ const COSEALG = {
50
+ ES256: -7,
51
+ EdDSA: -8,
52
+ ES384: -35,
53
+ ES512: -36,
54
+ PS256: -37,
55
+ PS384: -38,
56
+ PS512: -39,
57
+ ES256K: -47,
58
+ RS256: -257,
59
+ RS384: -258,
60
+ RS512: -259,
61
+ RS1: -65535
62
+ };
63
+ const COSECRV = {
64
+ P256: 1,
65
+ P384: 2,
66
+ P521: 3,
67
+ ED25519: 6,
68
+ SECP256K1: 8
69
+ };
70
+ const cose = {
71
+ COSEKEYS,
72
+ COSEKTY,
73
+ COSEALG,
74
+ COSECRV
75
+ };
76
+ const isoBase64URL = {
77
+ toBuffer(base64url) {
78
+ const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
79
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
80
+ const binary = atob(padded);
81
+ const bytes = new Uint8Array(binary.length);
82
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
83
+ return bytes;
84
+ },
85
+ fromBuffer(buffer, to = "base64url") {
86
+ const normalized = new Uint8Array(buffer);
87
+ let binary = "";
88
+ for (let i = 0; i < normalized.length; i++) binary += String.fromCharCode(normalized[i]);
89
+ const base64 = btoa(binary);
90
+ if (to === "base64") return base64;
91
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
92
+ },
93
+ toUTF8String(base64url) {
94
+ const bytes = isoBase64URL.toBuffer(base64url);
95
+ return new TextDecoder().decode(bytes);
96
+ },
97
+ fromUTF8String(utf8String) {
98
+ const bytes = new TextEncoder().encode(utf8String);
99
+ return isoBase64URL.fromBuffer(bytes);
100
+ }
101
+ };
102
+ const isoUint8Array = {
103
+ concat(arrays) {
104
+ const totalLength = arrays.reduce((sum, a) => sum + a.length, 0);
105
+ const result = new Uint8Array(totalLength);
106
+ let offset = 0;
107
+ for (const arr of arrays) {
108
+ result.set(arr, offset);
109
+ offset += arr.length;
110
+ }
111
+ return result;
112
+ },
113
+ areEqual(a, b) {
114
+ if (a.length !== b.length) return false;
115
+ return a.every((v, i) => v === b[i]);
116
+ },
117
+ toDataView(array) {
118
+ return new DataView(array.buffer, array.byteOffset, array.length);
119
+ },
120
+ fromHex(hex) {
121
+ const bytes = new Uint8Array(hex.length / 2);
122
+ for (let i = 0; i < hex.length; i += 2) bytes[i / 2] = Number.parseInt(hex.substring(i, i + 2), 16);
123
+ return bytes;
124
+ }
125
+ };
126
+ function decodeCBORInternal(data, offset) {
127
+ const major = data[offset] >> 5;
128
+ const additional = data[offset] & 31;
129
+ offset++;
130
+ let length;
131
+ if (additional < 24) length = additional;
132
+ else if (additional === 24) length = data[offset++];
133
+ else if (additional === 25) {
134
+ length = data[offset] << 8 | data[offset + 1];
135
+ offset += 2;
136
+ } else if (additional === 26) {
137
+ length = data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
138
+ offset += 4;
139
+ } else throw new Error(`CBOR: unsupported additional info ${additional}`);
140
+ switch (major) {
141
+ case 0: return [length, offset];
142
+ case 1: return [-1 - length, offset];
143
+ case 2: return [data.slice(offset, offset + length), offset + length];
144
+ case 3: return [new TextDecoder().decode(data.slice(offset, offset + length)), offset + length];
145
+ case 4: {
146
+ const arr = [];
147
+ for (let i = 0; i < length; i++) {
148
+ const [value, newOffset] = decodeCBORInternal(data, offset);
149
+ arr.push(value);
150
+ offset = newOffset;
151
+ }
152
+ return [arr, offset];
153
+ }
154
+ case 5: {
155
+ const map = /* @__PURE__ */ new Map();
156
+ for (let i = 0; i < length; i++) {
157
+ const [key, keyOffset] = decodeCBORInternal(data, offset);
158
+ const [value, valueOffset] = decodeCBORInternal(data, keyOffset);
159
+ map.set(key, value);
160
+ offset = valueOffset;
161
+ }
162
+ return [map, offset];
163
+ }
164
+ default: throw new Error(`CBOR: unsupported major type ${major}`);
165
+ }
166
+ }
167
+ function encodeCBORValue(value) {
168
+ if (value instanceof Uint8Array || value instanceof ArrayBuffer) {
169
+ const bytes = value instanceof Uint8Array ? value : new Uint8Array(value);
170
+ return [...encodeCBORHead(2, bytes.length), ...bytes];
171
+ }
172
+ if (typeof value === "number") {
173
+ if (value >= 0) return encodeCBORHead(0, value);
174
+ return encodeCBORHead(1, -1 - value);
175
+ }
176
+ if (typeof value === "string") {
177
+ const encoded = new TextEncoder().encode(value);
178
+ return [...encodeCBORHead(3, encoded.length), ...encoded];
179
+ }
180
+ if (Array.isArray(value)) {
181
+ const items = value.flatMap((v) => encodeCBORValue(v));
182
+ return [...encodeCBORHead(4, value.length), ...items];
183
+ }
184
+ if (value instanceof Map) {
185
+ const items = [];
186
+ for (const [k, v] of value) items.push(...encodeCBORValue(k), ...encodeCBORValue(v));
187
+ return [...encodeCBORHead(5, value.size), ...items];
188
+ }
189
+ throw new Error(`CBOR encode: unsupported type ${typeof value}`);
190
+ }
191
+ function encodeCBORHead(major, length) {
192
+ const prefix = major << 5;
193
+ if (length < 24) return [prefix | length];
194
+ if (length < 256) return [prefix | 24, length];
195
+ if (length < 65536) return [
196
+ prefix | 25,
197
+ length >> 8 & 255,
198
+ length & 255
199
+ ];
200
+ return [
201
+ prefix | 26,
202
+ length >> 24 & 255,
203
+ length >> 16 & 255,
204
+ length >> 8 & 255,
205
+ length & 255
206
+ ];
207
+ }
208
+ const isoCBOR = {
209
+ decodeFirst(input) {
210
+ const [value] = decodeCBORInternal(new Uint8Array(input), 0);
211
+ return value;
212
+ },
213
+ encode(input) {
214
+ return new Uint8Array(encodeCBORValue(input));
215
+ }
216
+ };
217
+ async function toHash(data, algorithm = COSEALG.ES256) {
218
+ const input = typeof data === "string" ? new TextEncoder().encode(data) : data;
219
+ if ([
220
+ COSEALG.ES256,
221
+ COSEALG.PS256,
222
+ COSEALG.RS256,
223
+ COSEALG.ES256K
224
+ ].includes(algorithm)) return sha256(input);
225
+ if ([
226
+ COSEALG.ES384,
227
+ COSEALG.PS384,
228
+ COSEALG.RS384
229
+ ].includes(algorithm)) return sha384(input);
230
+ if ([
231
+ COSEALG.ES512,
232
+ COSEALG.PS512,
233
+ COSEALG.RS512,
234
+ COSEALG.EdDSA
235
+ ].includes(algorithm)) return sha512(input);
236
+ return sha256(input);
237
+ }
238
+ function decodeClientDataJSON(data) {
239
+ return JSON.parse(isoBase64URL.toUTF8String(data));
240
+ }
241
+ function parseAuthenticatorData(authData) {
242
+ if (authData.byteLength < 37) throw new Error(`Authenticator data was ${authData.byteLength} bytes, expected at least 37 bytes`);
243
+ let pointer = 0;
244
+ const dataView = isoUint8Array.toDataView(authData);
245
+ const rpIdHash = authData.slice(pointer, pointer += 32);
246
+ const flagsBuf = authData.slice(pointer, pointer += 1);
247
+ const flagsInt = flagsBuf[0];
248
+ const flags = {
249
+ up: !!(flagsInt & 1),
250
+ uv: !!(flagsInt & 4),
251
+ be: !!(flagsInt & 8),
252
+ bs: !!(flagsInt & 16),
253
+ at: !!(flagsInt & 64),
254
+ ed: !!(flagsInt & 128),
255
+ flagsInt
256
+ };
257
+ const counterBuf = authData.slice(pointer, pointer + 4);
258
+ const counter = dataView.getUint32(pointer, false);
259
+ pointer += 4;
260
+ let aaguid;
261
+ let credentialID;
262
+ let credentialPublicKey;
263
+ if (flags.at) {
264
+ aaguid = authData.slice(pointer, pointer += 16);
265
+ const credIDLen = dataView.getUint16(pointer);
266
+ pointer += 2;
267
+ credentialID = authData.slice(pointer, pointer += credIDLen);
268
+ const firstDecoded = isoCBOR.decodeFirst(authData.slice(pointer));
269
+ const firstEncoded = isoCBOR.encode(firstDecoded);
270
+ credentialPublicKey = firstEncoded;
271
+ pointer += firstEncoded.byteLength;
272
+ }
273
+ let extensionsData;
274
+ let extensionsDataBuffer;
275
+ if (flags.ed) {
276
+ const firstDecoded = isoCBOR.decodeFirst(authData.slice(pointer));
277
+ extensionsDataBuffer = isoCBOR.encode(firstDecoded);
278
+ extensionsData = firstDecoded;
279
+ pointer += extensionsDataBuffer.byteLength;
280
+ }
281
+ return {
282
+ rpIdHash,
283
+ flagsBuf,
284
+ flags,
285
+ counter,
286
+ counterBuf,
287
+ aaguid,
288
+ credentialID,
289
+ credentialPublicKey,
290
+ extensionsData,
291
+ extensionsDataBuffer
292
+ };
293
+ }
294
+ function getCurveForCrv(crv) {
295
+ switch (crv) {
296
+ case COSECRV.P256: return {
297
+ curve: p256,
298
+ hash: sha256,
299
+ componentLen: 32
300
+ };
301
+ case COSECRV.P384: return {
302
+ curve: p384,
303
+ hash: sha384,
304
+ componentLen: 48
305
+ };
306
+ case COSECRV.P521: return {
307
+ curve: p521,
308
+ hash: sha512,
309
+ componentLen: 66
310
+ };
311
+ case COSECRV.SECP256K1: return {
312
+ curve: secp256k1,
313
+ hash: sha256,
314
+ componentLen: 32
315
+ };
316
+ default: throw new Error(`Unsupported COSE curve: ${crv}`);
317
+ }
318
+ }
319
+ async function verifySignature(opts) {
320
+ const { signature, data, credentialPublicKey } = opts;
321
+ const coseKey = isoCBOR.decodeFirst(credentialPublicKey);
322
+ const kty = coseKey.get(COSEKEYS.kty);
323
+ if (kty !== COSEKTY.EC2) throw new Error(`Unsupported COSE key type: ${kty} (only EC2 is supported)`);
324
+ const crv = coseKey.get(COSEKEYS.crv);
325
+ const x = coseKey.get(COSEKEYS.x);
326
+ const y = coseKey.get(COSEKEYS.y);
327
+ if (!x || !y) throw new Error("COSE public key missing x or y coordinate");
328
+ const { curve, hash, componentLen } = getCurveForCrv(crv);
329
+ const pubKeyBytes = new Uint8Array(1 + componentLen * 2);
330
+ pubKeyBytes[0] = 4;
331
+ pubKeyBytes.set(x.length <= componentLen ? x : x.slice(x.length - componentLen), 1 + (componentLen - x.length));
332
+ pubKeyBytes.set(y.length <= componentLen ? y : y.slice(y.length - componentLen), 1 + componentLen + (componentLen - y.length));
333
+ const msgHash = hash(data);
334
+ try {
335
+ const sig = curve.Signature.fromDER(signature);
336
+ return curve.verify(sig, msgHash, pubKeyBytes);
337
+ } catch {
338
+ return false;
339
+ }
340
+ }
341
+ function generateChallenge() {
342
+ return crypto.getRandomValues(new Uint8Array(32));
343
+ }
344
+ function convertAAGUIDToString(aaguid) {
345
+ const hex = Array.from(aaguid, (b) => b.toString(16).padStart(2, "0")).join("");
346
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
347
+ }
348
+ async function matchExpectedRPID(rpIdHash, expectedRPIDs) {
349
+ for (const rpID of expectedRPIDs) {
350
+ const expectedHash = sha256(new TextEncoder().encode(rpID));
351
+ if (isoUint8Array.areEqual(rpIdHash, expectedHash)) return rpID;
352
+ }
353
+ throw new Error(`Unexpected RP ID hash, expected one of: ${expectedRPIDs.join(", ")}`);
354
+ }
355
+ function parseBackupFlags(flags) {
356
+ const credentialDeviceType = flags.be ? "multiDevice" : "singleDevice";
357
+ const credentialBackedUp = flags.bs;
358
+ if (!flags.be && flags.bs) throw new Error("Credential indicates backup state but not backup eligibility");
359
+ return {
360
+ credentialDeviceType,
361
+ credentialBackedUp
362
+ };
363
+ }
364
+ async function generateRegistrationOptions(options) {
365
+ const { rpName, rpID, userName, userID, challenge = generateChallenge(), userDisplayName = "", timeout = 6e4, attestationType = "none", excludeCredentials = [], authenticatorSelection = {
366
+ residentKey: "preferred",
367
+ userVerification: "preferred"
368
+ }, extensions, supportedAlgorithmIDs = [
369
+ -8,
370
+ -7,
371
+ -257
372
+ ] } = options;
373
+ const pubKeyCredParams = supportedAlgorithmIDs.map((id) => ({
374
+ alg: id,
375
+ type: "public-key"
376
+ }));
377
+ if (authenticatorSelection.residentKey === void 0) {
378
+ if (authenticatorSelection.requireResidentKey) authenticatorSelection.residentKey = "required";
379
+ } else authenticatorSelection.requireResidentKey = authenticatorSelection.residentKey === "required";
380
+ let _challenge = challenge;
381
+ if (typeof _challenge === "string") _challenge = new TextEncoder().encode(_challenge);
382
+ let _userID = userID;
383
+ if (!_userID) _userID = crypto.getRandomValues(new Uint8Array(32));
384
+ return {
385
+ challenge: isoBase64URL.fromBuffer(_challenge),
386
+ rp: {
387
+ name: rpName,
388
+ id: rpID
389
+ },
390
+ user: {
391
+ id: isoBase64URL.fromBuffer(_userID),
392
+ name: userName,
393
+ displayName: userDisplayName
394
+ },
395
+ pubKeyCredParams,
396
+ timeout,
397
+ attestation: attestationType,
398
+ excludeCredentials: excludeCredentials.map((cred) => ({
399
+ ...cred,
400
+ id: cred.id.replace(/=+$/, ""),
401
+ type: "public-key"
402
+ })),
403
+ authenticatorSelection,
404
+ extensions: {
405
+ ...extensions,
406
+ credProps: true
407
+ }
408
+ };
409
+ }
410
+ async function generateAuthenticationOptions(options) {
411
+ const { rpID, allowCredentials, challenge = generateChallenge(), timeout = 6e4, userVerification = "preferred", extensions } = options;
412
+ let _challenge = challenge;
413
+ if (typeof _challenge === "string") _challenge = new TextEncoder().encode(_challenge);
414
+ return {
415
+ rpId: rpID,
416
+ challenge: isoBase64URL.fromBuffer(_challenge),
417
+ allowCredentials: allowCredentials?.map((cred) => ({
418
+ ...cred,
419
+ id: cred.id.replace(/=+$/, ""),
420
+ type: "public-key"
421
+ })),
422
+ timeout,
423
+ userVerification,
424
+ extensions
425
+ };
426
+ }
427
+ async function verifyRegistrationResponse(options) {
428
+ const { response, expectedChallenge, expectedOrigin, expectedRPID, expectedType, requireUserPresence = true, requireUserVerification = true, supportedAlgorithmIDs = [
429
+ -8,
430
+ -7,
431
+ -36,
432
+ -37,
433
+ -38,
434
+ -39,
435
+ -257,
436
+ -258,
437
+ -259,
438
+ -65535
439
+ ] } = options;
440
+ const { id, rawId, type: credentialType, response: attestationResponse } = response;
441
+ if (!id) throw new Error("Missing credential ID");
442
+ if (id !== rawId) throw new Error("Credential ID was not base64url-encoded");
443
+ if (credentialType !== "public-key") throw new Error(`Unexpected credential type ${credentialType}, expected "public-key"`);
444
+ const clientDataJSON = decodeClientDataJSON(attestationResponse.clientDataJSON);
445
+ const { type, origin, challenge } = clientDataJSON;
446
+ if (Array.isArray(expectedType)) {
447
+ if (!expectedType.includes(type)) throw new Error(`Unexpected registration response type "${type}", expected one of: ${expectedType.join(", ")}`);
448
+ } else if (expectedType) {
449
+ if (type !== expectedType) throw new Error(`Unexpected registration response type "${type}", expected "${expectedType}"`);
450
+ } else if (type !== "webauthn.create") throw new Error(`Unexpected registration response type: ${type}`);
451
+ if (typeof expectedChallenge === "function") {
452
+ if (!await expectedChallenge(challenge)) throw new Error(`Custom challenge verifier returned false for registration response challenge "${challenge}"`);
453
+ } else if (challenge !== expectedChallenge) throw new Error(`Unexpected registration response challenge "${challenge}", expected "${expectedChallenge}"`);
454
+ if (Array.isArray(expectedOrigin)) {
455
+ if (!expectedOrigin.includes(origin)) throw new Error(`Unexpected registration response origin "${origin}", expected one of: ${expectedOrigin.join(", ")}`);
456
+ } else if (origin !== expectedOrigin) throw new Error(`Unexpected registration response origin "${origin}", expected "${expectedOrigin}"`);
457
+ const attestationObject = isoBase64URL.toBuffer(attestationResponse.attestationObject);
458
+ const decodedAttestationObject = isoCBOR.decodeFirst(attestationObject);
459
+ const fmt = decodedAttestationObject.get("fmt");
460
+ const authData = decodedAttestationObject.get("authData");
461
+ const attStmt = decodedAttestationObject.get("attStmt");
462
+ const { aaguid, rpIdHash, flags, credentialID, counter, credentialPublicKey, extensionsData } = parseAuthenticatorData(authData);
463
+ let matchedRPID;
464
+ if (expectedRPID) matchedRPID = await matchExpectedRPID(rpIdHash, Array.isArray(expectedRPID) ? expectedRPID : [expectedRPID]);
465
+ if (requireUserPresence && !flags.up) throw new Error("User presence was required, but user was not present");
466
+ if (requireUserVerification && !flags.uv) throw new Error("User verification was required, but user could not be verified");
467
+ if (!credentialID) throw new Error("No credential ID was provided by authenticator");
468
+ if (!credentialPublicKey) throw new Error("No public key was provided by authenticator");
469
+ if (!aaguid) throw new Error("No AAGUID was present during registration");
470
+ const alg = isoCBOR.decodeFirst(credentialPublicKey).get(COSEKEYS.alg);
471
+ if (typeof alg !== "number") throw new Error("Credential public key was missing numeric alg");
472
+ if (!supportedAlgorithmIDs.includes(alg)) throw new Error(`Unexpected public key alg "${alg}", expected one of "${supportedAlgorithmIDs.join(", ")}"`);
473
+ let verified = false;
474
+ if (fmt === "none") {
475
+ if (attStmt.size > 0) throw new Error("None attestation had unexpected attestation statement");
476
+ verified = true;
477
+ } else if (fmt === "packed" && attStmt.size === 2 && attStmt.has("alg") && attStmt.has("sig")) {
478
+ const clientDataHash = await toHash(isoBase64URL.toBuffer(attestationResponse.clientDataJSON));
479
+ const signedData = isoUint8Array.concat([authData, clientDataHash]);
480
+ verified = await verifySignature({
481
+ signature: attStmt.get("sig"),
482
+ data: signedData,
483
+ credentialPublicKey
484
+ });
485
+ } else throw new Error(`Unsupported attestation format: "${fmt}". Only "none" and "packed" (self-attestation) are supported.`);
486
+ if (!verified) return { verified: false };
487
+ const { credentialDeviceType, credentialBackedUp } = parseBackupFlags(flags);
488
+ return {
489
+ verified: true,
490
+ registrationInfo: {
491
+ fmt,
492
+ aaguid: convertAAGUIDToString(aaguid),
493
+ credential: {
494
+ id: isoBase64URL.fromBuffer(credentialID),
495
+ publicKey: credentialPublicKey,
496
+ counter,
497
+ transports: response.response.transports
498
+ },
499
+ credentialType: "public-key",
500
+ attestationObject,
501
+ userVerified: flags.uv,
502
+ credentialDeviceType,
503
+ credentialBackedUp,
504
+ origin: clientDataJSON.origin,
505
+ rpID: matchedRPID,
506
+ authenticatorExtensionResults: extensionsData
507
+ }
508
+ };
509
+ }
510
+
511
+ //#endregion
512
+ export { COSEALG, COSECRV, COSEKEYS, COSEKTY, cose, decodeClientDataJSON, generateAuthenticationOptions, generateChallenge, generateRegistrationOptions, isoBase64URL, isoCBOR, isoUint8Array, parseAuthenticatorData, toHash, verifyRegistrationResponse, verifySignature, webauthn_exports };
@@ -5,6 +5,19 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __exportAll = (all, symbols) => {
9
+ let target = {};
10
+ for (var name in all) {
11
+ __defProp(target, name, {
12
+ get: all[name],
13
+ enumerable: true
14
+ });
15
+ }
16
+ if (symbols) {
17
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
18
+ }
19
+ return target;
20
+ };
8
21
  var __copyProps = (to, from, except, desc) => {
9
22
  if (from && typeof from === "object" || typeof from === "function") {
10
23
  for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
@@ -26,4 +39,5 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
39
 
27
40
  //#endregion
28
41
 
42
+ exports.__exportAll = __exportAll;
29
43
  exports.__toESM = __toESM;
package/lib/index.cjs CHANGED
@@ -6,6 +6,7 @@ const require_hasher_sha3 = require('./hasher/sha3.cjs');
6
6
  const require_signer_ed25519 = require('./signer/ed25519.cjs');
7
7
  const require_signer_secp256k1 = require('./signer/secp256k1.cjs');
8
8
  const require_signer_ethereum = require('./signer/ethereum.cjs');
9
+ const require_webauthn = require('./webauthn.cjs');
9
10
  const require_signer_passkey = require('./signer/passkey.cjs');
10
11
  let randombytes = require("randombytes");
11
12
  randombytes = require_rolldown_runtime.__toESM(randombytes);
@@ -189,4 +190,10 @@ exports.getHasher = getHasher;
189
190
  exports.getRandomBytes = getRandomBytes;
190
191
  exports.getSigner = getSigner;
191
192
  exports.toTxHash = toTxHash;
192
- exports.types = types;
193
+ exports.types = types;
194
+ Object.defineProperty(exports, 'webauthn', {
195
+ enumerable: true,
196
+ get: function () {
197
+ return require_webauthn.webauthn_exports;
198
+ }
199
+ });
package/lib/index.d.cts CHANGED
@@ -5,6 +5,7 @@ import { Ed25519Signer } from "./signer/ed25519.cjs";
5
5
  import { Secp256k1Signer } from "./signer/secp256k1.cjs";
6
6
  import { EthereumSigner } from "./signer/ethereum.cjs";
7
7
  import { PasskeySigner } from "./signer/passkey.cjs";
8
+ import { webauthn_d_exports } from "./webauthn.cjs";
8
9
  import { BytesType, EncodingType, KeyPairType } from "@ocap/util";
9
10
  import { LiteralUnion } from "type-fest";
10
11
 
@@ -238,4 +239,4 @@ declare function getRandomBytes(length: number, encoding?: 'Uint8Array'): Uint8A
238
239
  declare function getRandomBytes(length: number, encoding?: EncodingType): BytesType;
239
240
  declare const toTxHash: (buf: Buffer | Uint8Array) => string;
240
241
  //#endregion
241
- export { AddressType, HashFnType, HashType, Hasher, KeyType, RoleType, Signer, SignerType, getHasher, getRandomBytes, getSigner, toTxHash, types };
242
+ export { AddressType, HashFnType, HashType, Hasher, KeyType, RoleType, Signer, SignerType, getHasher, getRandomBytes, getSigner, toTxHash, types, webauthn_d_exports as webauthn };
@@ -2,14 +2,20 @@ Object.defineProperty(exports, '__esModule', { value: true });
2
2
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
3
3
  const require_signer_secp256k1 = require('./secp256k1.cjs');
4
4
  let _ocap_util = require("@ocap/util");
5
- let eth_lib_lib_account = require("eth-lib/lib/account");
6
- eth_lib_lib_account = require_rolldown_runtime.__toESM(eth_lib_lib_account);
7
- let eth_lib_lib_hash = require("eth-lib/lib/hash");
8
- eth_lib_lib_hash = require_rolldown_runtime.__toESM(eth_lib_lib_hash);
5
+ let _noble_hashes_sha3_js = require("@noble/hashes/sha3.js");
6
+ let _noble_hashes_utils_js = require("@noble/hashes/utils.js");
7
+ let _noble_curves_secp256k1 = require("@noble/curves/secp256k1");
9
8
 
10
9
  //#region src/signer/ethereum.ts
10
+ function toChecksumAddress(address) {
11
+ const addr = address.slice(2).toLowerCase();
12
+ const hash = (0, _noble_hashes_utils_js.bytesToHex)((0, _noble_hashes_sha3_js.keccak_256)(Buffer.from(addr)));
13
+ let result = "0x";
14
+ for (let i = 0; i < 40; i++) result += Number.parseInt(hash[i], 16) > 7 ? addr[i].toUpperCase() : addr[i];
15
+ return result;
16
+ }
11
17
  /**
12
- * Signer implementation for secp256k1, based on `elliptic`, and ethereum compatible
18
+ * Signer implementation for secp256k1, based on `@noble/curves`, and ethereum compatible
13
19
  *
14
20
  * @class EthereumSigner
15
21
  */
@@ -20,17 +26,25 @@ var EthereumSigner = class extends require_signer_secp256k1.Secp256k1Signer {
20
26
  }
21
27
  ethHash(data) {
22
28
  const messageBytes = (0, _ocap_util.hexToBytes)((0, _ocap_util.isHexStrict)(data) ? data : (0, _ocap_util.utf8ToHex)(data));
23
- const messageBuffer = Buffer.from(messageBytes);
24
29
  const preamble = `\x19Ethereum Signed Message:\n${messageBytes.length}`;
25
- const preambleBuffer = Uint8Array.from(Buffer.from(preamble));
26
- const ethMessage = Buffer.concat([preambleBuffer, Uint8Array.from(messageBuffer)]);
27
- return eth_lib_lib_hash.default.keccak256s(ethMessage);
30
+ const ethMessage = Buffer.concat([Buffer.from(preamble), Buffer.from(messageBytes)]);
31
+ return `0x${(0, _noble_hashes_utils_js.bytesToHex)((0, _noble_hashes_sha3_js.keccak_256)(new Uint8Array(ethMessage)))}`;
28
32
  }
29
33
  ethSign(data, privateKey) {
30
- return eth_lib_lib_account.default.sign(data, privateKey);
34
+ const msgHash = Buffer.from(data.slice(2), "hex");
35
+ const sk = Buffer.from(privateKey.slice(2), "hex");
36
+ const sig = _noble_curves_secp256k1.secp256k1.sign(msgHash, sk);
37
+ const v = (27 + sig.recovery).toString(16).padStart(2, "0");
38
+ return `0x${sig.toCompactHex()}${v}`;
31
39
  }
32
40
  ethRecover(data, signature) {
33
- return eth_lib_lib_account.default.recover(data, signature);
41
+ const sigHex = signature.slice(2);
42
+ const v = Number.parseInt(sigHex.slice(128, 130), 16);
43
+ const recovery = v < 2 ? v : 1 - v % 2;
44
+ const sig = _noble_curves_secp256k1.secp256k1.Signature.fromCompact(sigHex.slice(0, 128)).addRecoveryBit(recovery);
45
+ const msgHash = Buffer.from(data.slice(2), "hex");
46
+ const pubKeyHex = sig.recoverPublicKey(msgHash).toHex(false).slice(2);
47
+ return toChecksumAddress(`0x${(0, _noble_hashes_utils_js.bytesToHex)((0, _noble_hashes_sha3_js.keccak_256)(Buffer.from(pubKeyHex, "hex"))).slice(-40)}`);
34
48
  }
35
49
  };
36
50
  var ethereum_default = new EthereumSigner();
@@ -3,7 +3,7 @@ import { Secp256k1Signer } from "./secp256k1.cjs";
3
3
  //#region src/signer/ethereum.d.ts
4
4
 
5
5
  /**
6
- * Signer implementation for secp256k1, based on `elliptic`, and ethereum compatible
6
+ * Signer implementation for secp256k1, based on `@noble/curves`, and ethereum compatible
7
7
  *
8
8
  * @class EthereumSigner
9
9
  */
@@ -1,12 +1,12 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
2
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
3
3
  const require_protocols_signer = require('../protocols/signer.cjs');
4
+ const require_webauthn = require('../webauthn.cjs');
4
5
  let _ocap_util = require("@ocap/util");
5
- let _simplewebauthn_server_helpers = require("@simplewebauthn/server/helpers");
6
6
 
7
7
  //#region src/signer/passkey.ts
8
8
  /**
9
- * Signer implementation for passkey, based on `@simplewebauthn/server`
9
+ * Signer implementation for passkey, based on `@noble/curves`
10
10
  * Since passkey supports only verification, we do not need to implement the sign method
11
11
  * And passkeys can used multiple algorithms, we do not need to implement the algorithm selection
12
12
  *
@@ -34,11 +34,11 @@ var PasskeySigner = class extends require_protocols_signer.default {
34
34
  const parsed = JSON.parse(extra);
35
35
  if (!parsed.authenticatorData || !parsed.clientDataJSON) throw new Error("extra.authenticatorData or extra.clientDataJSON is required for passkey signature verification");
36
36
  const authDataBuffer = (0, _ocap_util.toBuffer)((0, _ocap_util.fromBase64)(parsed.authenticatorData));
37
- const clientDataHash = await (0, _simplewebauthn_server_helpers.toHash)(_simplewebauthn_server_helpers.isoBase64URL.toBuffer(parsed.clientDataJSON));
38
- if ((0, _simplewebauthn_server_helpers.decodeClientDataJSON)(parsed.clientDataJSON).challenge !== (0, _ocap_util.toBase64)(challenge)) throw new Error("challenge mismatch for passkey signature");
39
- return (0, _simplewebauthn_server_helpers.verifySignature)({
40
- signature: _simplewebauthn_server_helpers.isoBase64URL.toBuffer(typeof signature === "string" ? signature : (0, _ocap_util.toBase64)(signature)),
41
- data: _simplewebauthn_server_helpers.isoUint8Array.concat([Uint8Array.from(authDataBuffer), clientDataHash]),
37
+ const clientDataHash = await require_webauthn.toHash(require_webauthn.isoBase64URL.toBuffer(parsed.clientDataJSON));
38
+ if (require_webauthn.decodeClientDataJSON(parsed.clientDataJSON).challenge !== (0, _ocap_util.toBase64)(challenge)) throw new Error("challenge mismatch for passkey signature");
39
+ return require_webauthn.verifySignature({
40
+ signature: require_webauthn.isoBase64URL.toBuffer(typeof signature === "string" ? signature : (0, _ocap_util.toBase64)(signature)),
41
+ data: require_webauthn.isoUint8Array.concat([Uint8Array.from(authDataBuffer), clientDataHash]),
42
42
  credentialPublicKey: (0, _ocap_util.toUint8Array)(pk)
43
43
  });
44
44
  }
@@ -4,7 +4,7 @@ import { BytesType, EncodingType, KeyPairType } from "@ocap/util";
4
4
  //#region src/signer/passkey.d.ts
5
5
 
6
6
  /**
7
- * Signer implementation for passkey, based on `@simplewebauthn/server`
7
+ * Signer implementation for passkey, based on `@noble/curves`
8
8
  * Since passkey supports only verification, we do not need to implement the sign method
9
9
  * And passkeys can used multiple algorithms, we do not need to implement the algorithm selection
10
10
  *