ox 0.8.1 → 0.8.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/Ed25519/package.json +6 -0
  3. package/X25519/package.json +6 -0
  4. package/_cjs/core/Bls.js +10 -0
  5. package/_cjs/core/Bls.js.map +1 -1
  6. package/_cjs/core/Ed25519.js +53 -0
  7. package/_cjs/core/Ed25519.js.map +1 -0
  8. package/_cjs/core/P256.js +23 -0
  9. package/_cjs/core/P256.js.map +1 -1
  10. package/_cjs/core/Secp256k1.js +20 -0
  11. package/_cjs/core/Secp256k1.js.map +1 -1
  12. package/_cjs/core/WebAuthnP256.js +5 -4
  13. package/_cjs/core/WebAuthnP256.js.map +1 -1
  14. package/_cjs/core/WebCryptoP256.js +31 -0
  15. package/_cjs/core/WebCryptoP256.js.map +1 -1
  16. package/_cjs/core/X25519.js +45 -0
  17. package/_cjs/core/X25519.js.map +1 -0
  18. package/_cjs/index.js +4 -2
  19. package/_cjs/index.js.map +1 -1
  20. package/_cjs/version.js +1 -1
  21. package/_esm/core/Bls.js +109 -0
  22. package/_esm/core/Bls.js.map +1 -1
  23. package/_esm/core/Ed25519.js +121 -0
  24. package/_esm/core/Ed25519.js.map +1 -0
  25. package/_esm/core/P256.js +54 -2
  26. package/_esm/core/P256.js.map +1 -1
  27. package/_esm/core/Secp256k1.js +50 -0
  28. package/_esm/core/Secp256k1.js.map +1 -1
  29. package/_esm/core/WebAuthnP256.js +5 -4
  30. package/_esm/core/WebAuthnP256.js.map +1 -1
  31. package/_esm/core/WebCryptoP256.js +72 -0
  32. package/_esm/core/WebCryptoP256.js.map +1 -1
  33. package/_esm/core/X25519.js +97 -0
  34. package/_esm/core/X25519.js.map +1 -0
  35. package/_esm/index.js +65 -0
  36. package/_esm/index.js.map +1 -1
  37. package/_esm/version.js +1 -1
  38. package/_types/core/Bls.d.ts +124 -0
  39. package/_types/core/Bls.d.ts.map +1 -1
  40. package/_types/core/Ed25519.d.ts +156 -0
  41. package/_types/core/Ed25519.d.ts.map +1 -0
  42. package/_types/core/P256.d.ts +68 -2
  43. package/_types/core/P256.d.ts.map +1 -1
  44. package/_types/core/Secp256k1.d.ts +67 -0
  45. package/_types/core/Secp256k1.d.ts.map +1 -1
  46. package/_types/core/WebAuthnP256.d.ts +2 -0
  47. package/_types/core/WebAuthnP256.d.ts.map +1 -1
  48. package/_types/core/WebCryptoP256.d.ts +76 -1
  49. package/_types/core/WebCryptoP256.d.ts.map +1 -1
  50. package/_types/core/X25519.d.ts +127 -0
  51. package/_types/core/X25519.d.ts.map +1 -0
  52. package/_types/index.d.ts +65 -0
  53. package/_types/index.d.ts.map +1 -1
  54. package/_types/version.d.ts +1 -1
  55. package/core/Bls.ts +150 -0
  56. package/core/Ed25519.ts +237 -0
  57. package/core/P256.ts +114 -2
  58. package/core/Secp256k1.ts +110 -0
  59. package/core/WebAuthnP256.ts +9 -3
  60. package/core/WebCryptoP256.ts +141 -1
  61. package/core/X25519.ts +202 -0
  62. package/index.ts +67 -0
  63. package/package.json +11 -1
  64. package/version.ts +1 -1
@@ -0,0 +1,237 @@
1
+ import { ed25519 } from '@noble/curves/ed25519'
2
+ import * as Bytes from './Bytes.js'
3
+ import type * as Errors from './Errors.js'
4
+ import * as Hex from './Hex.js'
5
+
6
+ /** Re-export of noble/curves Ed25519 utilities. */
7
+ export const noble = ed25519
8
+
9
+ /**
10
+ * Creates a new Ed25519 key pair consisting of a private key and its corresponding public key.
11
+ *
12
+ * @example
13
+ * ```ts twoslash
14
+ * import { Ed25519 } from 'ox'
15
+ *
16
+ * const { privateKey, publicKey } = Ed25519.createKeyPair()
17
+ * ```
18
+ *
19
+ * @param options - The options to generate the key pair.
20
+ * @returns The generated key pair containing both private and public keys.
21
+ */
22
+ export function createKeyPair<as extends 'Hex' | 'Bytes' = 'Hex'>(
23
+ options: createKeyPair.Options<as> = {},
24
+ ): createKeyPair.ReturnType<as> {
25
+ const { as = 'Hex' } = options
26
+ const privateKey = randomPrivateKey({ as })
27
+ const publicKey = getPublicKey({ privateKey, as })
28
+
29
+ return {
30
+ privateKey: privateKey as never,
31
+ publicKey: publicKey as never,
32
+ }
33
+ }
34
+
35
+ export declare namespace createKeyPair {
36
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
37
+ /**
38
+ * Format of the returned private and public keys.
39
+ * @default 'Hex'
40
+ */
41
+ as?: as | 'Hex' | 'Bytes' | undefined
42
+ }
43
+
44
+ type ReturnType<as extends 'Hex' | 'Bytes'> = {
45
+ privateKey:
46
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
47
+ | (as extends 'Hex' ? Hex.Hex : never)
48
+ publicKey:
49
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
50
+ | (as extends 'Hex' ? Hex.Hex : never)
51
+ }
52
+
53
+ type ErrorType =
54
+ | Hex.fromBytes.ErrorType
55
+ | randomPrivateKey.ErrorType
56
+ | getPublicKey.ErrorType
57
+ | Errors.GlobalErrorType
58
+ }
59
+
60
+ /**
61
+ * Computes the Ed25519 public key from a provided private key.
62
+ *
63
+ * @example
64
+ * ```ts twoslash
65
+ * import { Ed25519 } from 'ox'
66
+ *
67
+ * const publicKey = Ed25519.getPublicKey({ privateKey: '0x...' })
68
+ * ```
69
+ *
70
+ * @param options - The options to compute the public key.
71
+ * @returns The computed public key.
72
+ */
73
+ export function getPublicKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
74
+ options: getPublicKey.Options<as>,
75
+ ): getPublicKey.ReturnType<as> {
76
+ const { as = 'Hex', privateKey } = options
77
+ const privateKeyBytes = Bytes.from(privateKey)
78
+ const publicKeyBytes = ed25519.getPublicKey(privateKeyBytes)
79
+ if (as === 'Hex') return Hex.fromBytes(publicKeyBytes) as never
80
+ return publicKeyBytes as never
81
+ }
82
+
83
+ export declare namespace getPublicKey {
84
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
85
+ /**
86
+ * Format of the returned public key.
87
+ * @default 'Hex'
88
+ */
89
+ as?: as | 'Hex' | 'Bytes' | undefined
90
+ /**
91
+ * Private key to compute the public key from.
92
+ */
93
+ privateKey: Hex.Hex | Bytes.Bytes
94
+ }
95
+
96
+ type ReturnType<as extends 'Hex' | 'Bytes'> =
97
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
98
+ | (as extends 'Hex' ? Hex.Hex : never)
99
+
100
+ type ErrorType =
101
+ | Bytes.from.ErrorType
102
+ | Hex.fromBytes.ErrorType
103
+ | Errors.GlobalErrorType
104
+ }
105
+
106
+ /**
107
+ * Generates a random Ed25519 private key.
108
+ *
109
+ * @example
110
+ * ```ts twoslash
111
+ * import { Ed25519 } from 'ox'
112
+ *
113
+ * const privateKey = Ed25519.randomPrivateKey()
114
+ * ```
115
+ *
116
+ * @param options - The options to generate the private key.
117
+ * @returns The generated private key.
118
+ */
119
+ export function randomPrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
120
+ options: randomPrivateKey.Options<as> = {},
121
+ ): randomPrivateKey.ReturnType<as> {
122
+ const { as = 'Hex' } = options
123
+ const bytes = ed25519.utils.randomPrivateKey()
124
+ if (as === 'Hex') return Hex.fromBytes(bytes) as never
125
+ return bytes as never
126
+ }
127
+
128
+ export declare namespace randomPrivateKey {
129
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
130
+ /**
131
+ * Format of the returned private key.
132
+ * @default 'Hex'
133
+ */
134
+ as?: as | 'Hex' | 'Bytes' | undefined
135
+ }
136
+
137
+ type ReturnType<as extends 'Hex' | 'Bytes'> =
138
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
139
+ | (as extends 'Hex' ? Hex.Hex : never)
140
+
141
+ type ErrorType = Hex.fromBytes.ErrorType | Errors.GlobalErrorType
142
+ }
143
+
144
+ /**
145
+ * Signs the payload with the provided private key and returns an Ed25519 signature.
146
+ *
147
+ * @example
148
+ * ```ts twoslash
149
+ * import { Ed25519 } from 'ox'
150
+ *
151
+ * const signature = Ed25519.sign({ // [!code focus]
152
+ * payload: '0xdeadbeef', // [!code focus]
153
+ * privateKey: '0x...' // [!code focus]
154
+ * }) // [!code focus]
155
+ * ```
156
+ *
157
+ * @param options - The signing options.
158
+ * @returns The Ed25519 signature.
159
+ */
160
+ export function sign<as extends 'Hex' | 'Bytes' = 'Hex'>(
161
+ options: sign.Options<as>,
162
+ ): sign.ReturnType<as> {
163
+ const { as = 'Hex', payload, privateKey } = options
164
+ const payloadBytes = Bytes.from(payload)
165
+ const privateKeyBytes = Bytes.from(privateKey)
166
+ const signatureBytes = ed25519.sign(payloadBytes, privateKeyBytes)
167
+ if (as === 'Hex') return Hex.fromBytes(signatureBytes) as never
168
+ return signatureBytes as never
169
+ }
170
+
171
+ export declare namespace sign {
172
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
173
+ /**
174
+ * Format of the returned signature.
175
+ * @default 'Hex'
176
+ */
177
+ as?: as | 'Hex' | 'Bytes' | undefined
178
+ /**
179
+ * Payload to sign.
180
+ */
181
+ payload: Hex.Hex | Bytes.Bytes
182
+ /**
183
+ * Ed25519 private key.
184
+ */
185
+ privateKey: Hex.Hex | Bytes.Bytes
186
+ }
187
+
188
+ type ReturnType<as extends 'Hex' | 'Bytes'> =
189
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
190
+ | (as extends 'Hex' ? Hex.Hex : never)
191
+
192
+ type ErrorType =
193
+ | Bytes.from.ErrorType
194
+ | Hex.fromBytes.ErrorType
195
+ | Errors.GlobalErrorType
196
+ }
197
+
198
+ /**
199
+ * Verifies a payload was signed by the provided public key.
200
+ *
201
+ * @example
202
+ * ```ts twoslash
203
+ * import { Ed25519 } from 'ox'
204
+ *
205
+ * const { privateKey, publicKey } = Ed25519.createKeyPair()
206
+ * const signature = Ed25519.sign({ payload: '0xdeadbeef', privateKey })
207
+ *
208
+ * const verified = Ed25519.verify({ // [!code focus]
209
+ * publicKey, // [!code focus]
210
+ * payload: '0xdeadbeef', // [!code focus]
211
+ * signature, // [!code focus]
212
+ * }) // [!code focus]
213
+ * ```
214
+ *
215
+ * @param options - The verification options.
216
+ * @returns Whether the payload was signed by the provided public key.
217
+ */
218
+ export function verify(options: verify.Options): boolean {
219
+ const { payload, publicKey, signature } = options
220
+ const payloadBytes = Bytes.from(payload)
221
+ const publicKeyBytes = Bytes.from(publicKey)
222
+ const signatureBytes = Bytes.from(signature)
223
+ return ed25519.verify(signatureBytes, payloadBytes, publicKeyBytes)
224
+ }
225
+
226
+ export declare namespace verify {
227
+ type Options = {
228
+ /** Payload that was signed. */
229
+ payload: Hex.Hex | Bytes.Bytes
230
+ /** Public key that signed the payload. */
231
+ publicKey: Hex.Hex | Bytes.Bytes
232
+ /** Signature of the payload. */
233
+ signature: Hex.Hex | Bytes.Bytes
234
+ }
235
+
236
+ type ErrorType = Bytes.from.ErrorType | Errors.GlobalErrorType
237
+ }
package/core/P256.ts CHANGED
@@ -9,6 +9,54 @@ import * as Entropy from './internal/entropy.js'
9
9
  /** Re-export of noble/curves P256 utilities. */
10
10
  export const noble = secp256r1
11
11
 
12
+ /**
13
+ * Creates a new P256 ECDSA key pair consisting of a private key and its corresponding public key.
14
+ *
15
+ * @example
16
+ * ```ts twoslash
17
+ * import { P256 } from 'ox'
18
+ *
19
+ * const { privateKey, publicKey } = P256.createKeyPair()
20
+ * ```
21
+ *
22
+ * @param options - The options to generate the key pair.
23
+ * @returns The generated key pair containing both private and public keys.
24
+ */
25
+ export function createKeyPair<as extends 'Hex' | 'Bytes' = 'Hex'>(
26
+ options: createKeyPair.Options<as> = {},
27
+ ): createKeyPair.ReturnType<as> {
28
+ const { as = 'Hex' } = options
29
+ const privateKey = randomPrivateKey({ as })
30
+ const publicKey = getPublicKey({ privateKey })
31
+
32
+ return {
33
+ privateKey: privateKey as never,
34
+ publicKey,
35
+ }
36
+ }
37
+
38
+ export declare namespace createKeyPair {
39
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
40
+ /**
41
+ * Format of the returned private key.
42
+ * @default 'Hex'
43
+ */
44
+ as?: as | 'Hex' | 'Bytes' | undefined
45
+ }
46
+
47
+ type ReturnType<as extends 'Hex' | 'Bytes'> = {
48
+ privateKey:
49
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
50
+ | (as extends 'Hex' ? Hex.Hex : never)
51
+ publicKey: PublicKey.PublicKey
52
+ }
53
+
54
+ type ErrorType =
55
+ | Hex.fromBytes.ErrorType
56
+ | PublicKey.from.ErrorType
57
+ | Errors.GlobalErrorType
58
+ }
59
+
12
60
  /**
13
61
  * Computes the P256 ECDSA public key from a provided private key.
14
62
  *
@@ -45,6 +93,71 @@ export declare namespace getPublicKey {
45
93
  type ErrorType = Errors.GlobalErrorType
46
94
  }
47
95
 
96
+ /**
97
+ * Computes a shared secret using ECDH (Elliptic Curve Diffie-Hellman) between a private key and a public key.
98
+ *
99
+ * @example
100
+ * ```ts twoslash
101
+ * import { P256 } from 'ox'
102
+ *
103
+ * const { privateKey: privateKeyA } = P256.createKeyPair()
104
+ * const { publicKey: publicKeyB } = P256.createKeyPair()
105
+ *
106
+ * const sharedSecret = P256.getSharedSecret({
107
+ * privateKey: privateKeyA,
108
+ * publicKey: publicKeyB
109
+ * })
110
+ * ```
111
+ *
112
+ * @param options - The options to compute the shared secret.
113
+ * @returns The computed shared secret.
114
+ */
115
+ export function getSharedSecret<as extends 'Hex' | 'Bytes' = 'Hex'>(
116
+ options: getSharedSecret.Options<as>,
117
+ ): getSharedSecret.ReturnType<as> {
118
+ const { as = 'Hex', privateKey, publicKey } = options
119
+ const point = secp256r1.ProjectivePoint.fromHex(
120
+ PublicKey.toHex(publicKey).slice(2),
121
+ )
122
+ const privateKeyHex =
123
+ typeof privateKey === 'string'
124
+ ? privateKey.slice(2)
125
+ : Hex.fromBytes(privateKey).slice(2)
126
+ const sharedPoint = point.multiply(
127
+ secp256r1.utils.normPrivateKeyToScalar(privateKeyHex),
128
+ )
129
+ const sharedSecret = sharedPoint.toRawBytes(true) // compressed format
130
+ if (as === 'Hex') return Hex.fromBytes(sharedSecret) as never
131
+ return sharedSecret as never
132
+ }
133
+
134
+ export declare namespace getSharedSecret {
135
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
136
+ /**
137
+ * Format of the returned shared secret.
138
+ * @default 'Hex'
139
+ */
140
+ as?: as | 'Hex' | 'Bytes' | undefined
141
+ /**
142
+ * Private key to use for the shared secret computation.
143
+ */
144
+ privateKey: Hex.Hex | Bytes.Bytes
145
+ /**
146
+ * Public key to use for the shared secret computation.
147
+ */
148
+ publicKey: PublicKey.PublicKey<boolean>
149
+ }
150
+
151
+ type ReturnType<as extends 'Hex' | 'Bytes'> =
152
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
153
+ | (as extends 'Hex' ? Hex.Hex : never)
154
+
155
+ type ErrorType =
156
+ | Hex.fromBytes.ErrorType
157
+ | PublicKey.toHex.ErrorType
158
+ | Errors.GlobalErrorType
159
+ }
160
+
48
161
  /**
49
162
  * Generates a random P256 ECDSA private key.
50
163
  *
@@ -204,8 +317,7 @@ export declare namespace sign {
204
317
  * ```ts twoslash
205
318
  * import { P256 } from 'ox'
206
319
  *
207
- * const privateKey = P256.randomPrivateKey()
208
- * const publicKey = P256.getPublicKey({ privateKey })
320
+ * const { privateKey, publicKey } = P256.createKeyPair()
209
321
  * const signature = P256.sign({ payload: '0xdeadbeef', privateKey })
210
322
  *
211
323
  * const verified = P256.verify({ // [!code focus]
package/core/Secp256k1.ts CHANGED
@@ -11,6 +11,54 @@ import type { OneOf } from './internal/types.js'
11
11
  /** Re-export of noble/curves secp256k1 utilities. */
12
12
  export const noble = secp256k1
13
13
 
14
+ /**
15
+ * Creates a new secp256k1 ECDSA key pair consisting of a private key and its corresponding public key.
16
+ *
17
+ * @example
18
+ * ```ts twoslash
19
+ * import { Secp256k1 } from 'ox'
20
+ *
21
+ * const { privateKey, publicKey } = Secp256k1.createKeyPair()
22
+ * ```
23
+ *
24
+ * @param options - The options to generate the key pair.
25
+ * @returns The generated key pair containing both private and public keys.
26
+ */
27
+ export function createKeyPair<as extends 'Hex' | 'Bytes' = 'Hex'>(
28
+ options: createKeyPair.Options<as> = {},
29
+ ): createKeyPair.ReturnType<as> {
30
+ const { as = 'Hex' } = options
31
+ const privateKey = randomPrivateKey({ as })
32
+ const publicKey = getPublicKey({ privateKey })
33
+
34
+ return {
35
+ privateKey: privateKey as never,
36
+ publicKey,
37
+ }
38
+ }
39
+
40
+ export declare namespace createKeyPair {
41
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
42
+ /**
43
+ * Format of the returned private key.
44
+ * @default 'Hex'
45
+ */
46
+ as?: as | 'Hex' | 'Bytes' | undefined
47
+ }
48
+
49
+ type ReturnType<as extends 'Hex' | 'Bytes'> = {
50
+ privateKey:
51
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
52
+ | (as extends 'Hex' ? Hex.Hex : never)
53
+ publicKey: PublicKey.PublicKey
54
+ }
55
+
56
+ type ErrorType =
57
+ | Hex.fromBytes.ErrorType
58
+ | PublicKey.from.ErrorType
59
+ | Errors.GlobalErrorType
60
+ }
61
+
14
62
  /**
15
63
  * Computes the secp256k1 ECDSA public key from a provided private key.
16
64
  *
@@ -48,6 +96,68 @@ export declare namespace getPublicKey {
48
96
  | Errors.GlobalErrorType
49
97
  }
50
98
 
99
+ /**
100
+ * Computes a shared secret using ECDH (Elliptic Curve Diffie-Hellman) between a private key and a public key.
101
+ *
102
+ * @example
103
+ * ```ts twoslash
104
+ * import { Secp256k1 } from 'ox'
105
+ *
106
+ * const { privateKey: privateKeyA } = Secp256k1.createKeyPair()
107
+ * const { publicKey: publicKeyB } = Secp256k1.createKeyPair()
108
+ *
109
+ * const sharedSecret = Secp256k1.getSharedSecret({
110
+ * privateKey: privateKeyA,
111
+ * publicKey: publicKeyB
112
+ * })
113
+ * ```
114
+ *
115
+ * @param options - The options to compute the shared secret.
116
+ * @returns The computed shared secret.
117
+ */
118
+ export function getSharedSecret<as extends 'Hex' | 'Bytes' = 'Hex'>(
119
+ options: getSharedSecret.Options<as>,
120
+ ): getSharedSecret.ReturnType<as> {
121
+ const { as = 'Hex', privateKey, publicKey } = options
122
+ const point = secp256k1.ProjectivePoint.fromHex(
123
+ PublicKey.toHex(publicKey).slice(2),
124
+ )
125
+ const sharedPoint = point.multiply(
126
+ secp256k1.utils.normPrivateKeyToScalar(Hex.from(privateKey).slice(2)),
127
+ )
128
+ const sharedSecret = sharedPoint.toRawBytes(true) // compressed format
129
+ if (as === 'Hex') return Hex.fromBytes(sharedSecret) as never
130
+ return sharedSecret as never
131
+ }
132
+
133
+ export declare namespace getSharedSecret {
134
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
135
+ /**
136
+ * Format of the returned shared secret.
137
+ * @default 'Hex'
138
+ */
139
+ as?: as | 'Hex' | 'Bytes' | undefined
140
+ /**
141
+ * Private key to use for the shared secret computation.
142
+ */
143
+ privateKey: Hex.Hex | Bytes.Bytes
144
+ /**
145
+ * Public key to use for the shared secret computation.
146
+ */
147
+ publicKey: PublicKey.PublicKey<boolean>
148
+ }
149
+
150
+ type ReturnType<as extends 'Hex' | 'Bytes'> =
151
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
152
+ | (as extends 'Hex' ? Hex.Hex : never)
153
+
154
+ type ErrorType =
155
+ | Hex.from.ErrorType
156
+ | PublicKey.toHex.ErrorType
157
+ | Hex.fromBytes.ErrorType
158
+ | Errors.GlobalErrorType
159
+ }
160
+
51
161
  /**
52
162
  * Generates a random ECDSA private key on the secp256k1 curve.
53
163
  *
@@ -241,13 +241,13 @@ export function getCredentialCreationOptions(
241
241
  },
242
242
  challenge = createChallenge,
243
243
  excludeCredentialIds,
244
+ extensions,
244
245
  name: name_,
245
246
  rp = {
246
247
  id: window.location.hostname,
247
248
  name: window.document.title,
248
249
  },
249
250
  user,
250
- extensions,
251
251
  } = options
252
252
  const name = (user?.name ?? name_)!
253
253
  return {
@@ -269,15 +269,15 @@ export function getCredentialCreationOptions(
269
269
  alg: -7, // p256
270
270
  },
271
271
  ],
272
+ ...(extensions && { extensions }),
272
273
  rp,
273
274
  user: {
274
275
  id: user?.id ?? Hash.keccak256(Bytes.fromString(name), { as: 'Bytes' }),
275
276
  name,
276
277
  displayName: user?.displayName ?? name,
277
278
  },
278
- extensions,
279
279
  },
280
- } as internal.CredentialCreationOptions
280
+ }
281
281
  }
282
282
 
283
283
  export declare namespace getCredentialCreationOptions {
@@ -374,6 +374,7 @@ export function getCredentialRequestOptions(
374
374
  const {
375
375
  credentialId,
376
376
  challenge,
377
+ extensions,
377
378
  rpId = window.location.hostname,
378
379
  userVerification = 'required',
379
380
  } = options
@@ -395,6 +396,7 @@ export function getCredentialRequestOptions(
395
396
  }
396
397
  : {}),
397
398
  challenge: Bytes.fromHex(challenge),
399
+ ...(extensions && { extensions }),
398
400
  rpId,
399
401
  userVerification,
400
402
  },
@@ -407,6 +409,10 @@ export declare namespace getCredentialRequestOptions {
407
409
  credentialId?: string | string[] | undefined
408
410
  /** The challenge to sign. */
409
411
  challenge: Hex.Hex
412
+ /** List of Web Authentication API credentials to use during creation or authentication. */
413
+ extensions?:
414
+ | internal.PublicKeyCredentialRequestOptions['extensions']
415
+ | undefined
410
416
  /** The relying party identifier to use. */
411
417
  rpId?: internal.PublicKeyCredentialRequestOptions['rpId'] | undefined
412
418
  /** The user verification requirement. */
@@ -1,7 +1,7 @@
1
1
  import { p256 } from '@noble/curves/p256'
2
2
  import * as Bytes from './Bytes.js'
3
3
  import type * as Errors from './Errors.js'
4
- import type * as Hex from './Hex.js'
4
+ import * as Hex from './Hex.js'
5
5
  import * as PublicKey from './PublicKey.js'
6
6
  import type * as Signature from './Signature.js'
7
7
  import type { Compute } from './internal/types.js'
@@ -68,6 +68,146 @@ export declare namespace createKeyPair {
68
68
  type ErrorType = PublicKey.from.ErrorType | Errors.GlobalErrorType
69
69
  }
70
70
 
71
+ /**
72
+ * Generates an ECDH P256 key pair for key agreement that includes:
73
+ *
74
+ * - a `privateKey` of type [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
75
+ * - a `publicKey` of type {@link ox#PublicKey.PublicKey}
76
+ *
77
+ * @example
78
+ * ```ts twoslash
79
+ * import { WebCryptoP256 } from 'ox'
80
+ *
81
+ * const { publicKey, privateKey } = await WebCryptoP256.createKeyPairECDH()
82
+ * // @log: {
83
+ * // @log: privateKey: CryptoKey {},
84
+ * // @log: publicKey: {
85
+ * // @log: x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
86
+ * // @log: y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
87
+ * // @log: prefix: 4,
88
+ * // @log: },
89
+ * // @log: }
90
+ * ```
91
+ *
92
+ * @param options - Options for creating the key pair.
93
+ * @returns The key pair.
94
+ */
95
+ export async function createKeyPairECDH(
96
+ options: createKeyPairECDH.Options = {},
97
+ ): Promise<createKeyPairECDH.ReturnType> {
98
+ const { extractable = false } = options
99
+ const keypair = await globalThis.crypto.subtle.generateKey(
100
+ {
101
+ name: 'ECDH',
102
+ namedCurve: 'P-256',
103
+ },
104
+ extractable,
105
+ ['deriveKey', 'deriveBits'],
106
+ )
107
+ const publicKey_raw = await globalThis.crypto.subtle.exportKey(
108
+ 'raw',
109
+ keypair.publicKey,
110
+ )
111
+ const publicKey = PublicKey.from(new Uint8Array(publicKey_raw))
112
+ return {
113
+ privateKey: keypair.privateKey,
114
+ publicKey,
115
+ }
116
+ }
117
+
118
+ export declare namespace createKeyPairECDH {
119
+ type Options = {
120
+ /** A boolean value indicating whether it will be possible to export the private key using `globalThis.crypto.subtle.exportKey()`. */
121
+ extractable?: boolean | undefined
122
+ }
123
+
124
+ type ReturnType = Compute<{
125
+ privateKey: CryptoKey
126
+ publicKey: PublicKey.PublicKey
127
+ }>
128
+
129
+ type ErrorType = PublicKey.from.ErrorType | Errors.GlobalErrorType
130
+ }
131
+
132
+ /**
133
+ * Computes a shared secret using ECDH (Elliptic Curve Diffie-Hellman) between a private key and a public key using Web Crypto APIs.
134
+ *
135
+ * @example
136
+ * ```ts twoslash
137
+ * import { WebCryptoP256 } from 'ox'
138
+ *
139
+ * const { privateKey: privateKeyA } = await WebCryptoP256.createKeyPairECDH()
140
+ * const { publicKey: publicKeyB } = await WebCryptoP256.createKeyPairECDH()
141
+ *
142
+ * const sharedSecret = await WebCryptoP256.getSharedSecret({
143
+ * privateKey: privateKeyA,
144
+ * publicKey: publicKeyB
145
+ * })
146
+ * ```
147
+ *
148
+ * @param options - The options to compute the shared secret.
149
+ * @returns The computed shared secret.
150
+ */
151
+ export async function getSharedSecret<as extends 'Hex' | 'Bytes' = 'Hex'>(
152
+ options: getSharedSecret.Options<as>,
153
+ ): Promise<getSharedSecret.ReturnType<as>> {
154
+ const { as = 'Hex', privateKey, publicKey } = options
155
+
156
+ if (privateKey.algorithm.name === 'ECDSA') {
157
+ throw new Error(
158
+ 'privateKey is not compatible with ECDH. please use `createKeyPairECDH` to create an ECDH key.',
159
+ )
160
+ }
161
+
162
+ const publicKeyCrypto = await globalThis.crypto.subtle.importKey(
163
+ 'raw',
164
+ PublicKey.toBytes(publicKey),
165
+ { name: 'ECDH', namedCurve: 'P-256' },
166
+ false,
167
+ [],
168
+ )
169
+
170
+ const sharedSecretBuffer = await globalThis.crypto.subtle.deriveBits(
171
+ {
172
+ name: 'ECDH',
173
+ public: publicKeyCrypto,
174
+ },
175
+ privateKey,
176
+ 256, // 32 bytes * 8 bits/byte
177
+ )
178
+
179
+ const sharedSecret = new Uint8Array(sharedSecretBuffer)
180
+ if (as === 'Hex') return Hex.fromBytes(sharedSecret) as never
181
+ return sharedSecret as never
182
+ }
183
+
184
+ export declare namespace getSharedSecret {
185
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
186
+ /**
187
+ * Format of the returned shared secret.
188
+ * @default 'Hex'
189
+ */
190
+ as?: as | 'Hex' | 'Bytes' | undefined
191
+ /**
192
+ * Private key to use for the shared secret computation (must be a CryptoKey for ECDH).
193
+ */
194
+ privateKey: CryptoKey
195
+ /**
196
+ * Public key to use for the shared secret computation.
197
+ */
198
+ publicKey: PublicKey.PublicKey<boolean>
199
+ }
200
+
201
+ type ReturnType<as extends 'Hex' | 'Bytes'> =
202
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
203
+ | (as extends 'Hex' ? Hex.Hex : never)
204
+
205
+ type ErrorType =
206
+ | PublicKey.toBytes.ErrorType
207
+ | Hex.fromBytes.ErrorType
208
+ | Errors.GlobalErrorType
209
+ }
210
+
71
211
  /**
72
212
  * Signs a payload with the provided `CryptoKey` private key and returns a P256 signature.
73
213
  *